diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index a68720a7c0..d2c88cb2fb 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -1524,6 +1524,8 @@ USER_PERMISSIONS_FEATURES_AUTOMATIONS = ( os.environ.get('USER_PERMISSIONS_FEATURES_AUTOMATIONS', 'False').lower() == 'true' ) +USER_PERMISSIONS_FEATURES_CALENDAR = os.environ.get('USER_PERMISSIONS_FEATURES_CALENDAR', 'True').lower() == 'true' + USER_PERMISSIONS_SETTINGS_INTERFACE = os.environ.get('USER_PERMISSIONS_SETTINGS_INTERFACE', 'True').lower() == 'true' @@ -1594,6 +1596,7 @@ DEFAULT_USER_PERMISSIONS = { 'code_interpreter': USER_PERMISSIONS_FEATURES_CODE_INTERPRETER, 'memories': USER_PERMISSIONS_FEATURES_MEMORIES, 'automations': USER_PERMISSIONS_FEATURES_AUTOMATIONS, + 'calendar': USER_PERMISSIONS_FEATURES_CALENDAR, }, 'settings': { 'interface': USER_PERMISSIONS_SETTINGS_INTERFACE, @@ -1624,6 +1627,18 @@ ENABLE_CHANNELS = PersistentConfig( os.environ.get('ENABLE_CHANNELS', 'False').lower() == 'true', ) +ENABLE_CALENDAR = PersistentConfig( + 'ENABLE_CALENDAR', + 'calendar.enable', + os.environ.get('ENABLE_CALENDAR', 'True').lower() == 'true', +) + +ENABLE_AUTOMATIONS = PersistentConfig( + 'ENABLE_AUTOMATIONS', + 'automations.enable', + os.environ.get('ENABLE_AUTOMATIONS', 'True').lower() == 'true', +) + AUTOMATION_MAX_COUNT = PersistentConfig( 'AUTOMATION_MAX_COUNT', 'automations.max_count', diff --git a/backend/open_webui/env.py b/backend/open_webui/env.py index a395a424bf..9a741d4696 100644 --- a/backend/open_webui/env.py +++ b/backend/open_webui/env.py @@ -696,6 +696,15 @@ ENABLE_CHAT_RESPONSE_BASE64_IMAGE_URL_CONVERSION = ( os.environ.get('ENABLE_CHAT_RESPONSE_BASE64_IMAGE_URL_CONVERSION', 'False').lower() == 'true' ) +# When enabled, uses a hardcoded extension-to-MIME dictionary as a last-resort +# fallback when both mimetypes.guess_type() and file.meta.content_type fail to +# determine the content type. This can help on minimal container images (e.g. +# wolfi-base) that lack /etc/mime.types AND have legacy files without stored +# content_type metadata. +ENABLE_IMAGE_CONTENT_TYPE_EXTENSION_FALLBACK = ( + os.environ.get('ENABLE_IMAGE_CONTENT_TYPE_EXTENSION_FALLBACK', 'False').lower() == 'true' +) + CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE = os.environ.get('CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE', '1') if CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE == '': diff --git a/backend/open_webui/internal/db.py b/backend/open_webui/internal/db.py index 9028a3a4c8..80acfc6e53 100644 --- a/backend/open_webui/internal/db.py +++ b/backend/open_webui/internal/db.py @@ -436,9 +436,19 @@ get_db = contextmanager(get_session) ASYNC_SQLALCHEMY_DATABASE_URL = _make_async_url(SQLALCHEMY_DATABASE_URL) if 'sqlite' in ASYNC_SQLALCHEMY_DATABASE_URL: + # Generous default — async coroutines + no session sharing = high connection demand. + _sqlite_pool_size = ( + DATABASE_POOL_SIZE + if isinstance(DATABASE_POOL_SIZE, int) and DATABASE_POOL_SIZE > 0 + else 512 + ) async_engine = create_async_engine( ASYNC_SQLALCHEMY_DATABASE_URL, connect_args={'check_same_thread': False}, + pool_size=_sqlite_pool_size, + pool_timeout=DATABASE_POOL_TIMEOUT, + pool_recycle=DATABASE_POOL_RECYCLE, + pool_pre_ping=True, ) @event.listens_for(async_engine.sync_engine, 'connect') diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 8d95f5b277..ba7f74c830 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -105,6 +105,7 @@ from open_webui.routers import ( scim, terminals, automations, + calendar, ) from open_webui.routers.retrieval import ( @@ -392,9 +393,11 @@ from open_webui.config import ( API_KEYS_ALLOWED_ENDPOINTS, ENABLE_FOLDERS, FOLDER_MAX_FILE_COUNT, + ENABLE_AUTOMATIONS, AUTOMATION_MAX_COUNT, AUTOMATION_MIN_INTERVAL, ENABLE_CHANNELS, + ENABLE_CALENDAR, ENABLE_NOTES, ENABLE_USER_STATUS, ENABLE_COMMUNITY_SHARING, @@ -671,9 +674,9 @@ async def lifespan(app: FastAPI): asyncio.create_task(periodic_usage_pool_cleanup()) asyncio.create_task(periodic_session_pool_cleanup()) - from open_webui.utils.automations import automation_worker_loop + from open_webui.utils.automations import scheduler_worker_loop - asyncio.create_task(automation_worker_loop(app)) + asyncio.create_task(scheduler_worker_loop(app)) if app.state.config.ENABLE_BASE_MODELS_CACHE: try: @@ -898,9 +901,11 @@ app.state.config.BANNERS = WEBUI_BANNERS app.state.config.ENABLE_FOLDERS = ENABLE_FOLDERS app.state.config.FOLDER_MAX_FILE_COUNT = FOLDER_MAX_FILE_COUNT +app.state.config.ENABLE_AUTOMATIONS = ENABLE_AUTOMATIONS app.state.config.AUTOMATION_MAX_COUNT = AUTOMATION_MAX_COUNT app.state.config.AUTOMATION_MIN_INTERVAL = AUTOMATION_MIN_INTERVAL app.state.config.ENABLE_CHANNELS = ENABLE_CHANNELS +app.state.config.ENABLE_CALENDAR = ENABLE_CALENDAR app.state.config.ENABLE_NOTES = ENABLE_NOTES app.state.config.ENABLE_COMMUNITY_SHARING = ENABLE_COMMUNITY_SHARING app.state.config.ENABLE_MESSAGE_RATING = ENABLE_MESSAGE_RATING @@ -1433,6 +1438,7 @@ if ENABLE_ADMIN_ANALYTICS: app.include_router(utils.router, prefix='/api/v1/utils', tags=['utils']) app.include_router(terminals.router, prefix='/api/v1/terminals', tags=['terminals']) app.include_router(automations.router, prefix='/api/v1/automations', tags=['automations']) +app.include_router(calendar.router, prefix='/api/v1/calendars', tags=['calendars']) # SCIM 2.0 API for identity management if ENABLE_SCIM: @@ -1871,7 +1877,8 @@ async def chat_completion( finally: raise # re-raise to ensure proper task cancellation handling except Exception as e: - log.error('Error processing chat payload: %s', e) + error_detail = e.detail if isinstance(e, HTTPException) else str(e) + log.error('Error processing chat payload: %s', error_detail) if metadata.get('chat_id') and metadata.get('message_id'): # Update the chat message with the error try: @@ -1881,7 +1888,7 @@ async def chat_completion( metadata['message_id'], { 'parentId': metadata.get('user_message_id', None), - 'error': {'content': str(e)}, + 'error': {'content': error_detail}, }, ) @@ -1890,7 +1897,7 @@ async def chat_completion( await event_emitter( { 'type': 'chat:message:error', - 'data': {'error': {'content': str(e)}}, + 'data': {'error': {'content': error_detail}}, } ) await event_emitter( @@ -2216,6 +2223,8 @@ async def get_app_config(request: Request): 'enable_folders': app.state.config.ENABLE_FOLDERS, 'folder_max_file_count': app.state.config.FOLDER_MAX_FILE_COUNT, 'enable_channels': app.state.config.ENABLE_CHANNELS, + 'enable_calendar': app.state.config.ENABLE_CALENDAR, + 'enable_automations': app.state.config.ENABLE_AUTOMATIONS, 'enable_notes': app.state.config.ENABLE_NOTES, 'enable_web_search': app.state.config.ENABLE_WEB_SEARCH, 'enable_code_execution': app.state.config.ENABLE_CODE_EXECUTION, diff --git a/backend/open_webui/migrations/env.py b/backend/open_webui/migrations/env.py index 82ede513ae..9f76dcdade 100644 --- a/backend/open_webui/migrations/env.py +++ b/backend/open_webui/migrations/env.py @@ -4,6 +4,7 @@ from logging.config import fileConfig from alembic import context from open_webui.models.auths import Auth from open_webui.env import DATABASE_URL, DATABASE_ENABLE_IAM_TOKEN_AUTH, DATABASE_PASSWORD, LOG_FORMAT +from open_webui.models.calendar import Calendar, CalendarEvent, CalendarEventAttendee # noqa: F401 from sqlalchemy import engine_from_config, pool, create_engine # this is the Alembic Config object, which provides diff --git a/backend/open_webui/migrations/versions/56359461a091_add_calendar_tables.py b/backend/open_webui/migrations/versions/56359461a091_add_calendar_tables.py new file mode 100644 index 0000000000..e556440f56 --- /dev/null +++ b/backend/open_webui/migrations/versions/56359461a091_add_calendar_tables.py @@ -0,0 +1,83 @@ +"""add calendar tables + +Revision ID: 56359461a091 +Revises: c1d2e3f4a5b6 +Create Date: 2026-04-19 16:20:58.162045 + +""" + +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = '56359461a091' +down_revision: Union[str, None] = 'c1d2e3f4a5b6' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + op.create_table( + 'calendar', + sa.Column('id', sa.Text(), nullable=False), + sa.Column('user_id', sa.Text(), nullable=False), + sa.Column('name', sa.Text(), nullable=False), + sa.Column('color', sa.Text(), nullable=True), + sa.Column('is_default', sa.Boolean(), nullable=False), + sa.Column('data', sa.JSON(), nullable=True), + sa.Column('meta', sa.JSON(), nullable=True), + sa.Column('created_at', sa.BigInteger(), nullable=False), + sa.Column('updated_at', sa.BigInteger(), nullable=False), + sa.PrimaryKeyConstraint('id'), + ) + op.create_index('ix_calendar_user', 'calendar', ['user_id'], unique=False) + + op.create_table( + 'calendar_event', + sa.Column('id', sa.Text(), nullable=False), + sa.Column('calendar_id', sa.Text(), nullable=False), + sa.Column('user_id', sa.Text(), nullable=False), + sa.Column('title', sa.Text(), nullable=False), + sa.Column('description', sa.Text(), nullable=True), + sa.Column('start_at', sa.BigInteger(), nullable=False), + sa.Column('end_at', sa.BigInteger(), nullable=True), + sa.Column('all_day', sa.Boolean(), nullable=False), + sa.Column('rrule', sa.Text(), nullable=True), + sa.Column('color', sa.Text(), nullable=True), + sa.Column('location', sa.Text(), nullable=True), + sa.Column('data', sa.JSON(), nullable=True), + sa.Column('meta', sa.JSON(), nullable=True), + sa.Column('is_cancelled', sa.Boolean(), nullable=False), + sa.Column('created_at', sa.BigInteger(), nullable=False), + sa.Column('updated_at', sa.BigInteger(), nullable=False), + sa.PrimaryKeyConstraint('id'), + ) + op.create_index('ix_calendar_event_calendar', 'calendar_event', ['calendar_id', 'start_at'], unique=False) + op.create_index('ix_calendar_event_user_date', 'calendar_event', ['user_id', 'start_at'], unique=False) + + op.create_table( + 'calendar_event_attendee', + sa.Column('id', sa.Text(), nullable=False), + sa.Column('event_id', sa.Text(), nullable=False), + sa.Column('user_id', sa.Text(), nullable=False), + sa.Column('status', sa.Text(), nullable=False), + sa.Column('meta', sa.JSON(), nullable=True), + sa.Column('created_at', sa.BigInteger(), nullable=False), + sa.Column('updated_at', sa.BigInteger(), nullable=False), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('event_id', 'user_id', name='uq_event_attendee'), + ) + op.create_index('ix_calendar_event_attendee_user', 'calendar_event_attendee', ['user_id', 'status'], unique=False) + + +def downgrade() -> None: + op.drop_index('ix_calendar_event_attendee_user', table_name='calendar_event_attendee') + op.drop_table('calendar_event_attendee') + op.drop_index('ix_calendar_event_user_date', table_name='calendar_event') + op.drop_index('ix_calendar_event_calendar', table_name='calendar_event') + op.drop_table('calendar_event') + op.drop_index('ix_calendar_user', table_name='calendar') + op.drop_table('calendar') diff --git a/backend/open_webui/models/automations.py b/backend/open_webui/models/automations.py index c891c3204e..05f449ad13 100644 --- a/backend/open_webui/models/automations.py +++ b/backend/open_webui/models/automations.py @@ -153,6 +153,14 @@ class AutomationTable: row = await db.get(Automation, id) return AutomationModel.model_validate(row) if row else None + async def get_active_by_user(self, user_id: str, db: Optional[AsyncSession] = None) -> list[AutomationModel]: + """Get active automations for a user (for calendar RRULE expansion).""" + async with get_async_db_context(db) as db: + result = await db.execute( + select(Automation).filter_by(user_id=user_id, is_active=True).order_by(Automation.created_at.desc()) + ) + return [AutomationModel.model_validate(r) for r in result.scalars().all()] + async def search_automations( self, user_id: str, @@ -273,9 +281,19 @@ class AutomationTable: from open_webui.utils.automations import next_run_ns + # Batch-fetch user timezones so rescheduling respects each + # user's local timezone instead of falling back to server time. + user_ids = list({row.user_id for row in rows}) + timezone_by_user_id: dict[str, Optional[str]] = {} + if user_ids: + from open_webui.models.users import User + + tz_result = await db.execute(select(User.id, User.timezone).where(User.id.in_(user_ids))) + timezone_by_user_id = {uid: tz for uid, tz in tz_result.all()} + for row in rows: row.last_run_at = now_ns - row.next_run_at = next_run_ns(row.data.get('rrule', '')) + row.next_run_at = next_run_ns(row.data.get('rrule', ''), tz=timezone_by_user_id.get(row.user_id)) await db.commit() @@ -372,6 +390,32 @@ class AutomationRunTable: await db.commit() return result.rowcount + async def get_runs_by_user_range( + self, + user_id: str, + start_ns: int, + end_ns: int, + limit: int = 500, + db: Optional[AsyncSession] = None, + ) -> list[tuple['AutomationRunModel', 'AutomationModel']]: + """Get runs within a date range for a user, joined with parent automation.""" + async with get_async_db_context(db) as db: + result = await db.execute( + select(AutomationRun, Automation) + .join(Automation, Automation.id == AutomationRun.automation_id) + .filter( + Automation.user_id == user_id, + AutomationRun.created_at >= start_ns, + AutomationRun.created_at < end_ns, + ) + .order_by(AutomationRun.created_at.desc()) + .limit(limit) + ) + return [ + (AutomationRunModel.model_validate(run), AutomationModel.model_validate(auto)) + for run, auto in result.all() + ] + Automations = AutomationTable() AutomationRuns = AutomationRunTable() diff --git a/backend/open_webui/models/calendar.py b/backend/open_webui/models/calendar.py new file mode 100644 index 0000000000..dbb070013e --- /dev/null +++ b/backend/open_webui/models/calendar.py @@ -0,0 +1,824 @@ +import time +import logging +from typing import Optional +from uuid import uuid4 + +from pydantic import BaseModel, ConfigDict, Field +from sqlalchemy import ( + Column, + Text, + JSON, + Boolean, + BigInteger, + Index, + UniqueConstraint, + select, + or_, + exists, + func, + delete, + update, +) +from sqlalchemy.ext.asyncio import AsyncSession + +from open_webui.internal.db import Base, get_async_db_context +from open_webui.models.access_grants import AccessGrantModel, AccessGrants +from open_webui.models.groups import Groups +from open_webui.models.users import User, UserModel, UserResponse + +log = logging.getLogger(__name__) + + +#################### +# Calendar DB Schema +#################### + + +class Calendar(Base): + __tablename__ = 'calendar' + + id = Column(Text, primary_key=True) + user_id = Column(Text, nullable=False) + name = Column(Text, nullable=False) + color = Column(Text, nullable=True) + is_default = Column(Boolean, nullable=False, default=False) + data = Column(JSON, nullable=True) + meta = Column(JSON, nullable=True) + + created_at = Column(BigInteger, nullable=False) + updated_at = Column(BigInteger, nullable=False) + + __table_args__ = (Index('ix_calendar_user', 'user_id'),) + + +class CalendarEvent(Base): + __tablename__ = 'calendar_event' + + id = Column(Text, primary_key=True) + calendar_id = Column(Text, nullable=False) + user_id = Column(Text, nullable=False) + title = Column(Text, nullable=False) + description = Column(Text, nullable=True) + start_at = Column(BigInteger, nullable=False) + end_at = Column(BigInteger, nullable=True) + all_day = Column(Boolean, nullable=False, default=False) + rrule = Column(Text, nullable=True) + color = Column(Text, nullable=True) + location = Column(Text, nullable=True) + data = Column(JSON, nullable=True) + meta = Column(JSON, nullable=True) + is_cancelled = Column(Boolean, nullable=False, default=False) + + created_at = Column(BigInteger, nullable=False) + updated_at = Column(BigInteger, nullable=False) + + __table_args__ = ( + Index('ix_calendar_event_calendar', 'calendar_id', 'start_at'), + Index('ix_calendar_event_user_date', 'user_id', 'start_at'), + ) + + +class CalendarEventAttendee(Base): + __tablename__ = 'calendar_event_attendee' + + id = Column(Text, primary_key=True) + event_id = Column(Text, nullable=False) + user_id = Column(Text, nullable=False) + status = Column(Text, nullable=False, default='pending') + meta = Column(JSON, nullable=True) + + created_at = Column(BigInteger, nullable=False) + updated_at = Column(BigInteger, nullable=False) + + __table_args__ = ( + UniqueConstraint('event_id', 'user_id', name='uq_event_attendee'), + Index('ix_calendar_event_attendee_user', 'user_id', 'status'), + ) + + +#################### +# Pydantic Models +#################### + + +class CalendarModel(BaseModel): + model_config = ConfigDict(from_attributes=True) + + id: str + user_id: str + name: str + color: Optional[str] = None + is_default: bool = False + is_system: bool = False + + data: Optional[dict] = None + meta: Optional[dict] = None + + access_grants: list[AccessGrantModel] = Field(default_factory=list) + + created_at: int + updated_at: int + + +class CalendarEventModel(BaseModel): + model_config = ConfigDict(from_attributes=True, extra='allow') + + id: str + calendar_id: str + user_id: str + title: str + description: Optional[str] = None + start_at: int + end_at: Optional[int] = None + all_day: bool = False + rrule: Optional[str] = None + color: Optional[str] = None + location: Optional[str] = None + data: Optional[dict] = None + meta: Optional[dict] = None + is_cancelled: bool = False + + attendees: list['CalendarEventAttendeeModel'] = Field(default_factory=list) + + created_at: int + updated_at: int + + +class CalendarEventAttendeeModel(BaseModel): + model_config = ConfigDict(from_attributes=True) + + id: str + event_id: str + user_id: str + status: str = 'pending' + meta: Optional[dict] = None + + created_at: int + updated_at: int + + +#################### +# Forms +#################### + + +class CalendarForm(BaseModel): + name: str + color: Optional[str] = None + data: Optional[dict] = None + meta: Optional[dict] = None + access_grants: Optional[list[dict]] = None + + +class CalendarUpdateForm(BaseModel): + name: Optional[str] = None + color: Optional[str] = None + data: Optional[dict] = None + meta: Optional[dict] = None + access_grants: Optional[list[dict]] = None + + +class CalendarEventForm(BaseModel): + calendar_id: str + title: str + description: Optional[str] = None + start_at: int + end_at: Optional[int] = None + all_day: bool = False + rrule: Optional[str] = None + color: Optional[str] = None + location: Optional[str] = None + data: Optional[dict] = None + meta: Optional[dict] = None + attendees: Optional[list[dict]] = None + + +class CalendarEventUpdateForm(BaseModel): + calendar_id: Optional[str] = None + title: Optional[str] = None + description: Optional[str] = None + start_at: Optional[int] = None + end_at: Optional[int] = None + all_day: Optional[bool] = None + rrule: Optional[str] = None + color: Optional[str] = None + location: Optional[str] = None + data: Optional[dict] = None + meta: Optional[dict] = None + is_cancelled: Optional[bool] = None + attendees: Optional[list[dict]] = None + + +class RSVPForm(BaseModel): + status: str # 'accepted' | 'declined' | 'tentative' | 'pending' + + +#################### +# Response Models +#################### + + +class CalendarEventUserResponse(CalendarEventModel): + user: Optional[UserResponse] = None + + +class CalendarEventListResponse(BaseModel): + items: list[CalendarEventUserResponse] + total: int + + +#################### +# Table Operations +#################### + + +class CalendarTable: + async def _get_access_grants(self, calendar_id: str, db: Optional[AsyncSession] = None) -> list[AccessGrantModel]: + return await AccessGrants.get_grants_by_resource('calendar', calendar_id, db=db) + + async def _to_calendar_model( + self, + cal: Calendar, + access_grants: Optional[list[AccessGrantModel]] = None, + db: Optional[AsyncSession] = None, + ) -> CalendarModel: + cal_data = CalendarModel.model_validate(cal).model_dump(exclude={'access_grants'}) + cal_data['access_grants'] = ( + access_grants if access_grants is not None else await self._get_access_grants(cal_data['id'], db=db) + ) + return CalendarModel.model_validate(cal_data) + + async def get_or_create_defaults(self, user_id: str, db: Optional[AsyncSession] = None) -> list[CalendarModel]: + """Return user's calendars, creating 'Personal' default if none exist.""" + async with get_async_db_context(db) as db: + result = await db.execute( + select(Calendar).filter(Calendar.user_id == user_id).order_by(Calendar.created_at.asc()) + ) + calendars = result.scalars().all() + + if calendars: + return [CalendarModel.model_validate(c) for c in calendars] + + now = int(time.time_ns()) + cal = Calendar( + id=str(uuid4()), + user_id=user_id, + name='Personal', + color='#3b82f6', + is_default=True, + created_at=now, + updated_at=now, + ) + db.add(cal) + await db.commit() + return [CalendarModel.model_validate(cal)] + + async def get_calendars_by_user(self, user_id: str, db: Optional[AsyncSession] = None) -> list[CalendarModel]: + """Owned + shared calendars.""" + async with get_async_db_context(db) as db: + user_groups = await Groups.get_groups_by_member_id(user_id, db=db) + user_group_ids = [g.id for g in user_groups] + + stmt = select(Calendar) + stmt = AccessGrants.has_permission_filter( + db=db, + query=stmt, + DocumentModel=Calendar, + filter={'user_id': user_id, 'group_ids': user_group_ids}, + resource_type='calendar', + permission='read', + ) + stmt = stmt.order_by(Calendar.created_at.asc()) + + result = await db.execute(stmt) + calendars = result.scalars().all() + + if not calendars: + return await self.get_or_create_defaults(user_id, db=db) + + cal_ids = [c.id for c in calendars] + grants_map = await AccessGrants.get_grants_by_resources('calendar', cal_ids, db=db) + + return [await self._to_calendar_model(c, access_grants=grants_map.get(c.id, []), db=db) for c in calendars] + + async def get_calendar_by_id(self, id: str, db: Optional[AsyncSession] = None) -> Optional[CalendarModel]: + async with get_async_db_context(db) as db: + result = await db.execute(select(Calendar).filter(Calendar.id == id)) + cal = result.scalars().first() + return await self._to_calendar_model(cal, db=db) if cal else None + + + + async def insert_new_calendar( + self, user_id: str, form_data: CalendarForm, db: Optional[AsyncSession] = None + ) -> Optional[CalendarModel]: + async with get_async_db_context(db) as db: + now = int(time.time_ns()) + cal = Calendar( + id=str(uuid4()), + user_id=user_id, + name=form_data.name, + color=form_data.color, + is_default=False, + data=form_data.data, + meta=form_data.meta, + created_at=now, + updated_at=now, + ) + db.add(cal) + await db.commit() + if form_data.access_grants is not None: + await AccessGrants.set_access_grants('calendar', cal.id, form_data.access_grants, db=db) + return await self._to_calendar_model(cal, db=db) + + async def update_calendar_by_id( + self, id: str, form_data: CalendarUpdateForm, db: Optional[AsyncSession] = None + ) -> Optional[CalendarModel]: + async with get_async_db_context(db) as db: + result = await db.execute(select(Calendar).filter(Calendar.id == id)) + cal = result.scalars().first() + if not cal: + return None + + update_data = form_data.model_dump(exclude_unset=True) + if 'name' in update_data: + cal.name = update_data['name'] + if 'color' in update_data: + cal.color = update_data['color'] + if 'data' in update_data: + cal.data = {**(cal.data or {}), **update_data['data']} + if 'meta' in update_data: + cal.meta = {**(cal.meta or {}), **update_data['meta']} + if 'access_grants' in update_data: + await AccessGrants.set_access_grants('calendar', id, update_data['access_grants'], db=db) + + cal.updated_at = int(time.time_ns()) + await db.commit() + return await self._to_calendar_model(cal, db=db) + + async def set_default_calendar( + self, user_id: str, calendar_id: str, db: Optional[AsyncSession] = None + ) -> Optional[CalendarModel]: + """Set a calendar as the user's default, clearing all others.""" + async with get_async_db_context(db) as db: + # Clear all defaults for this user + await db.execute( + update(Calendar) + .where(Calendar.user_id == user_id, Calendar.is_default == True) + .values(is_default=False) + ) + # Set the new default + result = await db.execute(select(Calendar).filter(Calendar.id == calendar_id, Calendar.user_id == user_id)) + cal = result.scalars().first() + if not cal: + return None + cal.is_default = True + cal.updated_at = int(time.time_ns()) + await db.commit() + return await self._to_calendar_model(cal, db=db) + + async def delete_calendar_by_id(self, id: str, db: Optional[AsyncSession] = None) -> bool: + """Delete a non-default calendar. Cascades to events, attendees, and grants.""" + try: + async with get_async_db_context(db) as db: + result = await db.execute(select(Calendar).filter(Calendar.id == id)) + cal = result.scalars().first() + if not cal or cal.is_default: + return False + + # Delete attendees for all events in this calendar + event_ids_result = await db.execute(select(CalendarEvent.id).filter(CalendarEvent.calendar_id == id)) + event_ids = [r[0] for r in event_ids_result.all()] + if event_ids: + await db.execute( + delete(CalendarEventAttendee).filter(CalendarEventAttendee.event_id.in_(event_ids)) + ) + + # Delete events + await db.execute(delete(CalendarEvent).filter(CalendarEvent.calendar_id == id)) + + # Delete access grants + await AccessGrants.revoke_all_access('calendar', id, db=db) + + # Delete calendar + await db.execute(delete(Calendar).filter(Calendar.id == id)) + await db.commit() + return True + except Exception: + return False + + +class CalendarEventTable: + async def _get_attendees( + self, event_id: str, db: Optional[AsyncSession] = None + ) -> list[CalendarEventAttendeeModel]: + async with get_async_db_context(db) as db: + result = await db.execute(select(CalendarEventAttendee).filter(CalendarEventAttendee.event_id == event_id)) + rows = result.scalars().all() + return [CalendarEventAttendeeModel.model_validate(r) for r in rows] + + async def _to_event_model( + self, + event: CalendarEvent, + attendees: Optional[list[CalendarEventAttendeeModel]] = None, + db: Optional[AsyncSession] = None, + ) -> CalendarEventModel: + event_data = CalendarEventModel.model_validate(event).model_dump(exclude={'attendees'}) + event_data['attendees'] = ( + attendees if attendees is not None else await self._get_attendees(event_data['id'], db=db) + ) + return CalendarEventModel.model_validate(event_data) + + async def insert_new_event( + self, user_id: str, form_data: CalendarEventForm, db: Optional[AsyncSession] = None + ) -> Optional[CalendarEventModel]: + async with get_async_db_context(db) as db: + now = int(time.time_ns()) + event = CalendarEvent( + id=str(uuid4()), + calendar_id=form_data.calendar_id, + user_id=user_id, + title=form_data.title, + description=form_data.description, + start_at=form_data.start_at, + end_at=form_data.end_at, + all_day=form_data.all_day, + rrule=form_data.rrule, + color=form_data.color, + location=form_data.location, + data=form_data.data, + meta=form_data.meta, + is_cancelled=False, + created_at=now, + updated_at=now, + ) + db.add(event) + await db.commit() + + # Add attendees + if form_data.attendees: + await CalendarEventAttendees.set_attendees(event.id, form_data.attendees, db=db) + + return await self._to_event_model(event, db=db) + + async def get_event_by_id(self, id: str, db: Optional[AsyncSession] = None) -> Optional[CalendarEventModel]: + async with get_async_db_context(db) as db: + result = await db.execute(select(CalendarEvent).filter(CalendarEvent.id == id)) + event = result.scalars().first() + return await self._to_event_model(event, db=db) if event else None + + async def get_events_by_range( + self, + user_id: str, + start: int, + end: int, + calendar_ids: Optional[list[str]] = None, + db: Optional[AsyncSession] = None, + ) -> list[CalendarEventUserResponse]: + """Fetch events visible to user within a date range. + + Visible events = events in owned/shared calendars + events user attends. + Recurring events are fetched if they have any rrule (expansion in Python). + """ + async with get_async_db_context(db) as db: + user_groups = await Groups.get_groups_by_member_id(user_id, db=db) + user_group_ids = [g.id for g in user_groups] + + # Get calendar IDs accessible to user + cal_stmt = select(Calendar.id) + cal_stmt = AccessGrants.has_permission_filter( + db=db, + query=cal_stmt, + DocumentModel=Calendar, + filter={'user_id': user_id, 'group_ids': user_group_ids}, + resource_type='calendar', + permission='read', + ) + cal_result = await db.execute(cal_stmt) + accessible_cal_ids = [r[0] for r in cal_result.all()] + + if calendar_ids: + # Filter to requested calendars only + accessible_cal_ids = [c for c in accessible_cal_ids if c in calendar_ids] + + # Also get event IDs where user is an attendee + attendee_event_ids_result = await db.execute( + select(CalendarEventAttendee.event_id).filter(CalendarEventAttendee.user_id == user_id) + ) + attendee_event_ids = [r[0] for r in attendee_event_ids_result.all()] + + # Build conditions for accessible events + conditions = [] + if accessible_cal_ids: + conditions.append(CalendarEvent.calendar_id.in_(accessible_cal_ids)) + if attendee_event_ids: + conditions.append(CalendarEvent.id.in_(attendee_event_ids)) + + if not conditions: + return [] + + # Build event query + stmt = ( + select(CalendarEvent, User) + .outerjoin(User, User.id == CalendarEvent.user_id) + .filter( + CalendarEvent.is_cancelled == False, + or_(*conditions), + or_( + # Non-recurring: overlaps the range + ( + CalendarEvent.rrule.is_(None) + & (CalendarEvent.start_at < end) + & or_( + CalendarEvent.end_at.is_(None) & (CalendarEvent.start_at >= start), + CalendarEvent.end_at.isnot(None) & (CalendarEvent.end_at > start), + ) + ), + # Recurring: fetch all (expansion in Python) + CalendarEvent.rrule.isnot(None), + ), + ) + .order_by(CalendarEvent.start_at.asc()) + ) + + result = await db.execute(stmt) + items = result.all() + + if not items: + return [] + + # Batch-load attendees for all events in one query (avoid N+1) + event_ids = [event.id for event, _user in items] + att_result = await db.execute( + select(CalendarEventAttendee).filter(CalendarEventAttendee.event_id.in_(event_ids)) + ) + att_rows = att_result.scalars().all() + att_map: dict[str, list[CalendarEventAttendeeModel]] = {} + for a in att_rows: + att_map.setdefault(a.event_id, []).append(CalendarEventAttendeeModel.model_validate(a)) + + events = [] + for event, user in items: + event_data = CalendarEventModel.model_validate(event).model_dump(exclude={'attendees'}) + event_data['attendees'] = att_map.get(event.id, []) + events.append( + CalendarEventUserResponse( + **event_data, + user=(UserResponse(**UserModel.model_validate(user).model_dump()) if user else None), + ) + ) + + return events + + async def search_events( + self, + user_id: str, + query: Optional[str] = None, + skip: int = 0, + limit: int = 30, + db: Optional[AsyncSession] = None, + ) -> CalendarEventListResponse: + async with get_async_db_context(db) as db: + user_groups = await Groups.get_groups_by_member_id(user_id, db=db) + user_group_ids = [g.id for g in user_groups] + + # Get accessible calendar IDs + cal_stmt = select(Calendar.id) + cal_stmt = AccessGrants.has_permission_filter( + db=db, + query=cal_stmt, + DocumentModel=Calendar, + filter={'user_id': user_id, 'group_ids': user_group_ids}, + resource_type='calendar', + permission='read', + ) + cal_result = await db.execute(cal_stmt) + accessible_cal_ids = [r[0] for r in cal_result.all()] + if not accessible_cal_ids: + return CalendarEventListResponse(items=[], total=0) + + stmt = ( + select(CalendarEvent, User) + .outerjoin(User, User.id == CalendarEvent.user_id) + .filter( + CalendarEvent.is_cancelled == False, + CalendarEvent.calendar_id.in_(accessible_cal_ids), + ) + ) + + if query: + search = f'%{query}%' + stmt = stmt.filter( + or_( + CalendarEvent.title.ilike(search), + CalendarEvent.description.ilike(search), + CalendarEvent.location.ilike(search), + ) + ) + + stmt = stmt.order_by(CalendarEvent.start_at.desc()) + + count_result = await db.execute(select(func.count()).select_from(stmt.subquery())) + total = count_result.scalar() + + if skip: + stmt = stmt.offset(skip) + if limit: + stmt = stmt.limit(limit) + + result = await db.execute(stmt) + items = result.all() + + if not items: + return CalendarEventListResponse(items=[], total=total) + + # Batch-load attendees + event_ids = [event.id for event, _user in items] + att_result = await db.execute( + select(CalendarEventAttendee).filter(CalendarEventAttendee.event_id.in_(event_ids)) + ) + att_rows = att_result.scalars().all() + att_map: dict[str, list[CalendarEventAttendeeModel]] = {} + for a in att_rows: + att_map.setdefault(a.event_id, []).append(CalendarEventAttendeeModel.model_validate(a)) + + events = [] + for event, user in items: + event_data = CalendarEventModel.model_validate(event).model_dump(exclude={'attendees'}) + event_data['attendees'] = att_map.get(event.id, []) + events.append( + CalendarEventUserResponse( + **event_data, + user=(UserResponse(**UserModel.model_validate(user).model_dump()) if user else None), + ) + ) + + return CalendarEventListResponse(items=events, total=total) + + async def update_event_by_id( + self, id: str, form_data: CalendarEventUpdateForm, db: Optional[AsyncSession] = None + ) -> Optional[CalendarEventModel]: + async with get_async_db_context(db) as db: + result = await db.execute(select(CalendarEvent).filter(CalendarEvent.id == id)) + event = result.scalars().first() + if not event: + return None + + update_data = form_data.model_dump(exclude_unset=True) + for field in [ + 'calendar_id', + 'title', + 'description', + 'start_at', + 'end_at', + 'all_day', + 'rrule', + 'color', + 'location', + 'is_cancelled', + ]: + if field in update_data: + setattr(event, field, update_data[field]) + + if 'data' in update_data and update_data['data'] is not None: + event.data = {**(event.data or {}), **update_data['data']} + if 'meta' in update_data and update_data['meta'] is not None: + event.meta = {**(event.meta or {}), **update_data['meta']} + + if 'attendees' in update_data and update_data['attendees'] is not None: + await CalendarEventAttendees.set_attendees(id, update_data['attendees'], db=db) + + event.updated_at = int(time.time_ns()) + await db.commit() + return await self._to_event_model(event, db=db) + + async def get_upcoming_events( + self, + now_ns: int, + default_lookahead_ns: int, + db: Optional[AsyncSession] = None, + ) -> list[tuple[CalendarEventModel, Optional[str]]]: + """Events starting between now and now + lookahead, for alert processing. + + Per-event lookahead is read from meta.alert_minutes (falls back to + default_lookahead_ns). Returns (event, user_timezone) pairs. + """ + from open_webui.models.users import User as UserRow + + # Use the maximum possible lookahead (60 min) to cast a wide net; + # per-event filtering happens in Python after fetching. + max_lookahead_ns = max(default_lookahead_ns, 60 * 60 * 1_000_000_000) + upper = now_ns + max_lookahead_ns + + async with get_async_db_context(db) as db: + result = await db.execute( + select(CalendarEvent, UserRow.timezone) + .outerjoin(UserRow, UserRow.id == CalendarEvent.user_id) + .filter( + CalendarEvent.is_cancelled == False, + CalendarEvent.start_at >= now_ns, + CalendarEvent.start_at <= upper, + ) + ) + rows = result.all() + + events = [] + for event, tz in rows: + model = CalendarEventModel.model_validate(event) + # Determine per-event alert window + alert_minutes = None + if model.meta and 'alert_minutes' in model.meta: + alert_minutes = model.meta['alert_minutes'] + + if alert_minutes is not None: + if alert_minutes < 0: + # alert_minutes < 0 means "no alert" + continue + event_lookahead_ns = alert_minutes * 60 * 1_000_000_000 + else: + event_lookahead_ns = default_lookahead_ns + + if model.start_at <= now_ns + event_lookahead_ns: + events.append((model, tz)) + + return events + + async def delete_event_by_id(self, id: str, db: Optional[AsyncSession] = None) -> bool: + try: + async with get_async_db_context(db) as db: + await db.execute(delete(CalendarEventAttendee).filter(CalendarEventAttendee.event_id == id)) + await db.execute(delete(CalendarEvent).filter(CalendarEvent.id == id)) + await db.commit() + return True + except Exception: + return False + + +class CalendarEventAttendeeTable: + async def set_attendees( + self, event_id: str, attendees: list[dict], db: Optional[AsyncSession] = None + ) -> list[CalendarEventAttendeeModel]: + """Replace all attendees for an event. + + Each dict in attendees: {user_id: str, status?: str, meta?: dict} + """ + async with get_async_db_context(db) as db: + # Remove existing + await db.execute(delete(CalendarEventAttendee).filter(CalendarEventAttendee.event_id == event_id)) + + now = int(time.time_ns()) + models = [] + for att in attendees: + row = CalendarEventAttendee( + id=str(uuid4()), + event_id=event_id, + user_id=att['user_id'], + status=att.get('status', 'pending'), + meta=att.get('meta'), + created_at=now, + updated_at=now, + ) + db.add(row) + models.append(CalendarEventAttendeeModel.model_validate(row)) + + await db.commit() + return models + + async def update_rsvp( + self, event_id: str, user_id: str, status: str, db: Optional[AsyncSession] = None + ) -> Optional[CalendarEventAttendeeModel]: + async with get_async_db_context(db) as db: + result = await db.execute( + select(CalendarEventAttendee).filter( + CalendarEventAttendee.event_id == event_id, + CalendarEventAttendee.user_id == user_id, + ) + ) + att = result.scalars().first() + if not att: + return None + + att.status = status + att.updated_at = int(time.time_ns()) + await db.commit() + return CalendarEventAttendeeModel.model_validate(att) + + async def get_attendees_by_event( + self, event_id: str, db: Optional[AsyncSession] = None + ) -> list[CalendarEventAttendeeModel]: + async with get_async_db_context(db) as db: + result = await db.execute(select(CalendarEventAttendee).filter(CalendarEventAttendee.event_id == event_id)) + return [CalendarEventAttendeeModel.model_validate(r) for r in result.scalars().all()] + + async def get_events_by_attendee(self, user_id: str, db: Optional[AsyncSession] = None) -> list[str]: + """Return event IDs where user is an attendee.""" + async with get_async_db_context(db) as db: + result = await db.execute( + select(CalendarEventAttendee.event_id).filter(CalendarEventAttendee.user_id == user_id) + ) + return [r[0] for r in result.all()] + + +Calendars = CalendarTable() +CalendarEvents = CalendarEventTable() +CalendarEventAttendees = CalendarEventAttendeeTable() diff --git a/backend/open_webui/models/chat_messages.py b/backend/open_webui/models/chat_messages.py index bd9c720fa4..0758e0354d 100644 --- a/backend/open_webui/models/chat_messages.py +++ b/backend/open_webui/models/chat_messages.py @@ -313,7 +313,6 @@ class ChatMessageTable: stmt = select(ChatMessage.model_id, func.count(ChatMessage.id).label('count')).filter( ChatMessage.role == 'assistant', ChatMessage.model_id.isnot(None), - ~ChatMessage.user_id.like('shared-%'), ) if start_date: @@ -368,7 +367,6 @@ class ChatMessageTable: ChatMessage.role == 'assistant', ChatMessage.model_id.isnot(None), ChatMessage.usage.isnot(None), - ~ChatMessage.user_id.like('shared-%'), ) if start_date: @@ -430,7 +428,6 @@ class ChatMessageTable: ChatMessage.role == 'assistant', ChatMessage.user_id.isnot(None), ChatMessage.usage.isnot(None), - ~ChatMessage.user_id.like('shared-%'), ) if start_date: @@ -465,7 +462,7 @@ class ChatMessageTable: from open_webui.models.groups import GroupMember stmt = select(ChatMessage.user_id, func.count(ChatMessage.id).label('count')).filter( - ~ChatMessage.user_id.like('shared-%') + ChatMessage.role == 'assistant', ) if start_date: @@ -491,7 +488,7 @@ class ChatMessageTable: from open_webui.models.groups import GroupMember stmt = select(ChatMessage.chat_id, func.count(ChatMessage.id).label('count')).filter( - ~ChatMessage.user_id.like('shared-%') + ChatMessage.role == 'assistant', ) if start_date: @@ -521,7 +518,6 @@ class ChatMessageTable: stmt = select(ChatMessage.created_at, ChatMessage.model_id).filter( ChatMessage.role == 'assistant', ChatMessage.model_id.isnot(None), - ~ChatMessage.user_id.like('shared-%'), ) if start_date: @@ -568,7 +564,6 @@ class ChatMessageTable: stmt = select(ChatMessage.created_at, ChatMessage.model_id).filter( ChatMessage.role == 'assistant', ChatMessage.model_id.isnot(None), - ~ChatMessage.user_id.like('shared-%'), ) if start_date: diff --git a/backend/open_webui/retrieval/loaders/mistral.py b/backend/open_webui/retrieval/loaders/mistral.py index e46863a96a..b3d274ee7c 100644 --- a/backend/open_webui/retrieval/loaders/mistral.py +++ b/backend/open_webui/retrieval/loaders/mistral.py @@ -9,7 +9,7 @@ from typing import List, Dict, Any from contextlib import asynccontextmanager from langchain_core.documents import Document -from open_webui.env import GLOBAL_LOG_LEVEL +from open_webui.env import GLOBAL_LOG_LEVEL, AIOHTTP_CLIENT_SESSION_SSL logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL) log = logging.getLogger(__name__) @@ -285,6 +285,7 @@ class MistralLoader: data=writer, headers=self.headers, timeout=aiohttp.ClientTimeout(total=self.upload_timeout), + ssl=AIOHTTP_CLIENT_SESSION_SSL, ) as response: return await self._handle_response_async(response) @@ -333,6 +334,7 @@ class MistralLoader: headers=headers, params=params, timeout=aiohttp.ClientTimeout(total=self.url_timeout), + ssl=AIOHTTP_CLIENT_SESSION_SSL, ) as response: return await self._handle_response_async(response) @@ -404,6 +406,7 @@ class MistralLoader: json=payload, headers=headers, timeout=aiohttp.ClientTimeout(total=self.ocr_timeout), + ssl=AIOHTTP_CLIENT_SESSION_SSL, ) as response: ocr_response = await self._handle_response_async(response) @@ -436,7 +439,8 @@ class MistralLoader: async with session.delete( url=f'{self.base_url}/files/{file_id}', headers=self.headers, - timeout=aiohttp.ClientTimeout(total=self.cleanup_timeout), # Shorter timeout for cleanup + timeout=aiohttp.ClientTimeout(total=self.cleanup_timeout), + ssl=AIOHTTP_CLIENT_SESSION_SSL, ) as response: return await self._handle_response_async(response) diff --git a/backend/open_webui/retrieval/web/utils.py b/backend/open_webui/retrieval/web/utils.py index cfe0f71b85..cd5c3a946d 100644 --- a/backend/open_webui/retrieval/web/utils.py +++ b/backend/open_webui/retrieval/web/utils.py @@ -45,6 +45,7 @@ from open_webui.config import ( WEB_FETCH_FILTER_LIST, ) from open_webui.utils.misc import is_string_allowed +from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL log = logging.getLogger(__name__) @@ -511,6 +512,8 @@ class SafeWebBaseLoader(WebBaseLoader): ) if not self.session.verify: kwargs['ssl'] = False + else: + kwargs['ssl'] = AIOHTTP_CLIENT_SESSION_SSL async with session.get( url, diff --git a/backend/open_webui/routers/audio.py b/backend/open_webui/routers/audio.py index 42327059e6..5260bd873c 100644 --- a/backend/open_webui/routers/audio.py +++ b/backend/open_webui/routers/audio.py @@ -1304,6 +1304,7 @@ async def get_available_models(request: Request) -> list[dict]: try: async with session.get( f'{request.app.state.config.TTS_OPENAI_API_BASE_URL}/audio/models', + ssl=AIOHTTP_CLIENT_SESSION_SSL, ) as response: response.raise_for_status() data = await response.json() @@ -1315,6 +1316,7 @@ async def get_available_models(request: Request) -> list[dict]: try: async with session.get( f'{request.app.state.config.TTS_OPENAI_API_BASE_URL}/models', + ssl=AIOHTTP_CLIENT_SESSION_SSL, ) as response: response.raise_for_status() data = await response.json() @@ -1335,6 +1337,7 @@ async def get_available_models(request: Request) -> list[dict]: 'xi-api-key': request.app.state.config.TTS_API_KEY, 'Content-Type': 'application/json', }, + ssl=AIOHTTP_CLIENT_SESSION_SSL, ) as response: response.raise_for_status() models = await response.json() @@ -1362,6 +1365,7 @@ async def get_available_voices(request) -> dict: async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session: async with session.get( f'{request.app.state.config.TTS_OPENAI_API_BASE_URL}/audio/voices', + ssl=AIOHTTP_CLIENT_SESSION_SSL, ) as response: response.raise_for_status() data = await response.json() @@ -1401,7 +1405,7 @@ async def get_available_voices(request) -> dict: timeout = aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST) async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session: - async with session.get(url, headers=headers) as response: + async with session.get(url, headers=headers, ssl=AIOHTTP_CLIENT_SESSION_SSL) as response: response.raise_for_status() voices = await response.json() @@ -1422,6 +1426,7 @@ async def get_available_voices(request) -> dict: headers={ 'Authorization': f'Bearer {api_key}', }, + ssl=AIOHTTP_CLIENT_SESSION_SSL, ) as response: response.raise_for_status() voices_data = await response.json() @@ -1456,6 +1461,7 @@ async def get_elevenlabs_voices(api_key: str) -> dict: 'xi-api-key': api_key, 'Content-Type': 'application/json', }, + ssl=AIOHTTP_CLIENT_SESSION_SSL, ) as response: response.raise_for_status() voices_data = await response.json() diff --git a/backend/open_webui/routers/auths.py b/backend/open_webui/routers/auths.py index 651e123b64..2a6f0f6dcd 100644 --- a/backend/open_webui/routers/auths.py +++ b/backend/open_webui/routers/auths.py @@ -810,7 +810,7 @@ async def signout(request: Request, response: Response, db: AsyncSession = Depen oauth_id_token = session.token.get('id_token') try: async with ClientSession(trust_env=True) as session: - async with session.get(oauth_server_metadata_url) as r: + async with session.get(oauth_server_metadata_url, ssl=AIOHTTP_CLIENT_SESSION_SSL) as r: if r.status == 200: openid_data = await r.json() logout_url = openid_data.get('end_session_endpoint') @@ -971,7 +971,9 @@ async def get_admin_config(request: Request, user=Depends(get_admin_user)): 'FOLDER_MAX_FILE_COUNT': request.app.state.config.FOLDER_MAX_FILE_COUNT, 'AUTOMATION_MAX_COUNT': request.app.state.config.AUTOMATION_MAX_COUNT, 'AUTOMATION_MIN_INTERVAL': request.app.state.config.AUTOMATION_MIN_INTERVAL, + 'ENABLE_AUTOMATIONS': request.app.state.config.ENABLE_AUTOMATIONS, 'ENABLE_CHANNELS': request.app.state.config.ENABLE_CHANNELS, + 'ENABLE_CALENDAR': request.app.state.config.ENABLE_CALENDAR, 'ENABLE_MEMORIES': request.app.state.config.ENABLE_MEMORIES, 'ENABLE_NOTES': request.app.state.config.ENABLE_NOTES, 'ENABLE_USER_WEBHOOKS': request.app.state.config.ENABLE_USER_WEBHOOKS, @@ -999,7 +1001,9 @@ class AdminConfig(BaseModel): FOLDER_MAX_FILE_COUNT: Optional[int | str] = None AUTOMATION_MAX_COUNT: Optional[int | str] = None AUTOMATION_MIN_INTERVAL: Optional[int | str] = None + ENABLE_AUTOMATIONS: bool ENABLE_CHANNELS: bool + ENABLE_CALENDAR: bool ENABLE_MEMORIES: bool ENABLE_NOTES: bool ENABLE_USER_WEBHOOKS: bool @@ -1030,7 +1034,9 @@ async def update_admin_config(request: Request, form_data: AdminConfig, user=Dep request.app.state.config.AUTOMATION_MIN_INTERVAL = ( int(form_data.AUTOMATION_MIN_INTERVAL) if form_data.AUTOMATION_MIN_INTERVAL else '' ) + request.app.state.config.ENABLE_AUTOMATIONS = form_data.ENABLE_AUTOMATIONS request.app.state.config.ENABLE_CHANNELS = form_data.ENABLE_CHANNELS + request.app.state.config.ENABLE_CALENDAR = form_data.ENABLE_CALENDAR request.app.state.config.ENABLE_MEMORIES = form_data.ENABLE_MEMORIES request.app.state.config.ENABLE_NOTES = form_data.ENABLE_NOTES @@ -1073,7 +1079,9 @@ async def update_admin_config(request: Request, form_data: AdminConfig, user=Dep 'FOLDER_MAX_FILE_COUNT': request.app.state.config.FOLDER_MAX_FILE_COUNT, 'AUTOMATION_MAX_COUNT': request.app.state.config.AUTOMATION_MAX_COUNT, 'AUTOMATION_MIN_INTERVAL': request.app.state.config.AUTOMATION_MIN_INTERVAL, + 'ENABLE_AUTOMATIONS': request.app.state.config.ENABLE_AUTOMATIONS, 'ENABLE_CHANNELS': request.app.state.config.ENABLE_CHANNELS, + 'ENABLE_CALENDAR': request.app.state.config.ENABLE_CALENDAR, 'ENABLE_MEMORIES': request.app.state.config.ENABLE_MEMORIES, 'ENABLE_NOTES': request.app.state.config.ENABLE_NOTES, 'ENABLE_USER_WEBHOOKS': request.app.state.config.ENABLE_USER_WEBHOOKS, diff --git a/backend/open_webui/routers/automations.py b/backend/open_webui/routers/automations.py index d68bd8e2c6..ed33c4e8cb 100644 --- a/backend/open_webui/routers/automations.py +++ b/backend/open_webui/routers/automations.py @@ -39,6 +39,11 @@ PAGE_ITEM_COUNT = 30 async def check_automations_permission(request, user): + if not request.app.state.config.ENABLE_AUTOMATIONS: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ERROR_MESSAGES.UNAUTHORIZED, + ) if user.role != 'admin' and not await has_permission( user.id, 'features.automations', request.app.state.config.USER_PERMISSIONS ): diff --git a/backend/open_webui/routers/calendar.py b/backend/open_webui/routers/calendar.py new file mode 100644 index 0000000000..152b932234 --- /dev/null +++ b/backend/open_webui/routers/calendar.py @@ -0,0 +1,391 @@ +import logging +import time +from typing import Optional + +from fastapi import APIRouter, Depends, HTTPException, Request, status + +from open_webui.models.calendar import ( + Calendars, + CalendarEvents, + CalendarEventAttendees, + CalendarForm, + CalendarUpdateForm, + CalendarEventForm, + CalendarEventUpdateForm, + CalendarModel, + CalendarEventModel, + CalendarEventUserResponse, + CalendarEventListResponse, + RSVPForm, +) +from open_webui.models.access_grants import AccessGrants +from open_webui.models.groups import Groups +from open_webui.models.users import UserModel +from open_webui.utils.auth import get_verified_user +from open_webui.utils.access_control import has_permission +from open_webui.utils.calendar import expand_recurring_event +from open_webui.constants import ERROR_MESSAGES + +log = logging.getLogger(__name__) + +router = APIRouter() + +SCHEDULED_TASKS_CALENDAR_ID = '__scheduled_tasks__' + + +async def check_calendar_permission(request: Request, user): + """Check global feature flag AND per-user permission for calendar access.""" + if not request.app.state.config.ENABLE_CALENDAR: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ERROR_MESSAGES.UNAUTHORIZED, + ) + if user.role != 'admin' and not await has_permission( + user.id, 'features.calendar', request.app.state.config.USER_PERMISSIONS + ): + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ERROR_MESSAGES.UNAUTHORIZED, + ) + + +async def _user_has_automations(request: Request, user) -> bool: + """Check if automations feature is available to this user.""" + if not getattr(request.app.state.config, 'ENABLE_AUTOMATIONS', False): + return False + if user.role == 'admin': + return True + return await has_permission( + user.id, 'features.automations', request.app.state.config.USER_PERMISSIONS + ) + + +async def _check_calendar_access(calendar_id: str, user: UserModel, permission: str = 'write') -> CalendarModel: + """Verify user has access to a calendar. Returns the calendar or raises 403/404.""" + cal = await Calendars.get_calendar_by_id(calendar_id) + if not cal: + raise HTTPException(status_code=404, detail='Calendar not found') + if cal.user_id == user.id or user.role == 'admin': + return cal + user_groups = await Groups.get_groups_by_member_id(user.id) + user_group_ids = [g.id for g in user_groups] + if await AccessGrants.has_access( + user_id=user.id, + resource_type='calendar', + resource_id=cal.id, + permission=permission, + user_group_ids=user_group_ids, + ): + return cal + raise HTTPException(status_code=403, detail='Access denied') + + +#################### +# Calendar CRUD (static paths first) +#################### + + +@router.get('/', response_model=list[CalendarModel]) +async def get_calendars(request: Request, user: UserModel = Depends(get_verified_user)): + """List user's calendars (owned + shared), plus a virtual Scheduled Tasks calendar + when automations are available.""" + await check_calendar_permission(request, user) + calendars = await Calendars.get_calendars_by_user(user.id) + + if await _user_has_automations(request, user): + now = int(time.time_ns()) + calendars.append( + CalendarModel( + id=SCHEDULED_TASKS_CALENDAR_ID, + user_id=user.id, + name='Scheduled Tasks', + color='#8b5cf6', + is_default=False, + is_system=True, + created_at=now, + updated_at=now, + ) + ) + + return calendars + + +@router.post('/create', response_model=CalendarModel) +async def create_calendar(request: Request, form_data: CalendarForm, user: UserModel = Depends(get_verified_user)): + """Create a new user calendar.""" + await check_calendar_permission(request, user) + return await Calendars.insert_new_calendar(user.id, form_data) + + +#################### +# Event CRUD (before /{calendar_id} to avoid route conflicts) +#################### + + +@router.get('/events') +async def get_events( + request: Request, + start: str, + end: str, + calendar_ids: Optional[str] = None, + user: UserModel = Depends(get_verified_user), +): + """Get events in date range. + + Args: + start: ISO 8601 datetime string (e.g. 2026-04-01T00:00:00) + end: ISO 8601 datetime string (e.g. 2026-05-01T00:00:00) + calendar_ids: optional comma-separated list to filter + + Includes: + - Stored events from the database + - Virtual events computed from active automation RRULEs (Scheduled Tasks calendar) + """ + await check_calendar_permission(request, user) + from datetime import datetime + + try: + start_dt = datetime.fromisoformat(start.replace('Z', '+00:00')) + end_dt = datetime.fromisoformat(end.replace('Z', '+00:00')) + except ValueError: + raise HTTPException(status_code=400, detail='Invalid date format. Use ISO 8601 (e.g. 2026-04-01T00:00:00)') + + NS = 1_000_000 + start_ns = int(start_dt.timestamp() * 1000) * NS + end_ns = int(end_dt.timestamp() * 1000) * NS + cal_id_list = calendar_ids.split(',') if calendar_ids else None + + # 1. Stored events + events = await CalendarEvents.get_events_by_range( + user_id=user.id, + start=start_ns, + end=end_ns, + calendar_ids=cal_id_list, + ) + + # Expand recurring stored events + expanded = [] + for event in events: + event_dict = event.model_dump() + if event_dict.get('rrule'): + instances = expand_recurring_event(event_dict, start_ns, end_ns, tz=user.timezone) + for inst in instances: + expanded.append(CalendarEventUserResponse(**{**inst, 'user': event.user})) + else: + expanded.append(event) + + # 2. Virtual automation events (Scheduled Tasks calendar) + if await _user_has_automations(request, user) and ( + cal_id_list is None or SCHEDULED_TASKS_CALENDAR_ID in cal_id_list + ): + try: + from open_webui.models.automations import Automations, AutomationRuns + + # Future runs: expand RRULEs for active automations only + active_automations = await Automations.get_active_by_user(user.id) + for auto in active_automations: + rrule_str = auto.data.get('rrule', '') if auto.data else '' + if not rrule_str: + continue + + virtual = { + 'id': f'auto_{auto.id}', + 'calendar_id': SCHEDULED_TASKS_CALENDAR_ID, + 'user_id': user.id, + 'title': auto.name, + 'description': auto.data.get('prompt', '') if auto.data else '', + 'start_at': auto.next_run_at or 0, + 'end_at': None, + 'all_day': False, + 'rrule': rrule_str, + 'color': None, + 'location': None, + 'data': None, + 'meta': {'automation_id': auto.id}, + 'is_cancelled': False, + 'attendees': [], + 'created_at': auto.created_at, + 'updated_at': auto.updated_at, + 'user': None, + } + + # Only expand into the future — past runs are handled below + now_ns = int(time.time_ns()) + rrule_start = max(start_ns, now_ns) + instances = expand_recurring_event(virtual, rrule_start, end_ns, tz=user.timezone) + for inst in instances: + expanded.append(CalendarEventUserResponse(**inst)) + + # Past runs: single range query joined with automation + runs_with_auto = await AutomationRuns.get_runs_by_user_range(user.id, start_ns, end_ns) + for run, auto in runs_with_auto: + expanded.append( + CalendarEventUserResponse( + id=f'run_{run.id}', + calendar_id=SCHEDULED_TASKS_CALENDAR_ID, + user_id=user.id, + title=auto.name, + description=run.error if run.status == 'error' else '', + start_at=run.created_at, + end_at=None, + all_day=False, + color=None, + location=None, + data=None, + meta={ + 'automation_id': auto.id, + 'run_id': run.id, + 'chat_id': run.chat_id, + 'status': run.status, + }, + is_cancelled=False, + attendees=[], + created_at=run.created_at, + updated_at=run.created_at, + user=None, + ) + ) + except Exception as e: + log.warning(f'Failed to compute automation events: {e}', exc_info=True) + + return [e.model_dump() if hasattr(e, 'model_dump') else e for e in expanded] + + +@router.post('/events/create', response_model=CalendarEventModel) +async def create_event(request: Request, form_data: CalendarEventForm, user: UserModel = Depends(get_verified_user)): + await check_calendar_permission(request, user) + await _check_calendar_access(form_data.calendar_id, user, 'write') + return await CalendarEvents.insert_new_event(user.id, form_data) + + +@router.get('/events/search', response_model=CalendarEventListResponse) +async def search_events( + request: Request, + query: Optional[str] = None, + skip: int = 0, + limit: int = 30, + user: UserModel = Depends(get_verified_user), +): + await check_calendar_permission(request, user) + return await CalendarEvents.search_events(user_id=user.id, query=query, skip=skip, limit=limit) + + +@router.get('/events/{event_id}', response_model=CalendarEventModel) +async def get_event(request: Request, event_id: str, user: UserModel = Depends(get_verified_user)): + await check_calendar_permission(request, user) + event = await CalendarEvents.get_event_by_id(event_id) + if not event: + raise HTTPException(status_code=404, detail='Event not found') + + await _check_calendar_access(event.calendar_id, user, 'read') + + return event + + +@router.post('/events/{event_id}/update', response_model=CalendarEventModel) +async def update_event( + request: Request, event_id: str, form_data: CalendarEventUpdateForm, user: UserModel = Depends(get_verified_user) +): + await check_calendar_permission(request, user) + event = await CalendarEvents.get_event_by_id(event_id) + if not event: + raise HTTPException(status_code=404, detail='Event not found') + + await _check_calendar_access(event.calendar_id, user, 'write') + + updated = await CalendarEvents.update_event_by_id(event_id, form_data) + if not updated: + raise HTTPException(status_code=500, detail='Failed to update') + return updated + + +@router.delete('/events/{event_id}/delete') +async def delete_event(request: Request, event_id: str, user: UserModel = Depends(get_verified_user)): + await check_calendar_permission(request, user) + event = await CalendarEvents.get_event_by_id(event_id) + if not event: + raise HTTPException(status_code=404, detail='Event not found') + + await _check_calendar_access(event.calendar_id, user, 'write') + + result = await CalendarEvents.delete_event_by_id(event_id) + if not result: + raise HTTPException(status_code=500, detail='Failed to delete') + return {'status': True} + + +@router.post('/events/{event_id}/rsvp', response_model=dict) +async def rsvp_event( + request: Request, event_id: str, form_data: RSVPForm, user: UserModel = Depends(get_verified_user) +): + """Update own RSVP status for an event.""" + await check_calendar_permission(request, user) + if form_data.status not in ('accepted', 'declined', 'tentative', 'pending'): + raise HTTPException(status_code=400, detail='Invalid status') + + result = await CalendarEventAttendees.update_rsvp(event_id, user.id, form_data.status) + if not result: + raise HTTPException(status_code=404, detail='Not an attendee of this event') + return {'status': True, 'rsvp': result.status} + + +#################### +# Calendar by ID (dynamic path — MUST come after /events* routes) +#################### + + +@router.get('/{calendar_id}', response_model=CalendarModel) +async def get_calendar_by_id(request: Request, calendar_id: str, user: UserModel = Depends(get_verified_user)): + await check_calendar_permission(request, user) + cal = await _check_calendar_access(calendar_id, user, 'read') + return cal + + +@router.post('/{calendar_id}/update', response_model=CalendarModel) +async def update_calendar( + request: Request, calendar_id: str, form_data: CalendarUpdateForm, user: UserModel = Depends(get_verified_user) +): + await check_calendar_permission(request, user) + cal = await _check_calendar_access(calendar_id, user, 'write') + + # Only owner/admin can change access grants + if form_data.access_grants is not None and cal.user_id != user.id and user.role != 'admin': + raise HTTPException(status_code=403, detail='Only owner can manage sharing') + + updated = await Calendars.update_calendar_by_id(calendar_id, form_data) + if not updated: + raise HTTPException(status_code=500, detail='Failed to update') + return updated + + +@router.delete('/{calendar_id}/delete') +async def delete_calendar(request: Request, calendar_id: str, user: UserModel = Depends(get_verified_user)): + await check_calendar_permission(request, user) + + # Block deletion of the virtual Scheduled Tasks calendar + if calendar_id == SCHEDULED_TASKS_CALENDAR_ID: + raise HTTPException(status_code=400, detail='System calendars cannot be deleted') + + cal = await _check_calendar_access(calendar_id, user, 'write') + + # Only owner/admin can delete + if cal.user_id != user.id and user.role != 'admin': + raise HTTPException(status_code=403, detail='Only owner can delete calendar') + + # Block deletion of default calendar + if cal.is_default: + raise HTTPException(status_code=400, detail='Default calendar cannot be deleted') + + result = await Calendars.delete_calendar_by_id(calendar_id) + if not result: + raise HTTPException(status_code=500, detail='Failed to delete') + return {'status': True} + + +@router.post('/{calendar_id}/default') +async def set_default_calendar(request: Request, calendar_id: str, user: UserModel = Depends(get_verified_user)): + await check_calendar_permission(request, user) + cal = await Calendars.set_default_calendar(user.id, calendar_id) + if not cal: + raise HTTPException(status_code=404, detail='Calendar not found') + return cal diff --git a/backend/open_webui/routers/channels.py b/backend/open_webui/routers/channels.py index a771b95920..22feb1b8f6 100644 --- a/backend/open_webui/routers/channels.py +++ b/backend/open_webui/routers/channels.py @@ -923,15 +923,13 @@ async def model_response_handler(request, channel, message, user, db=None): thread_history = [] images = [] - message_users = {} + + # Batch fetch all users in a single query (fixes N+1 problem) + user_ids = list({message.user_id for message in thread_messages}) + message_users = {user.id: user for user in await Users.get_users_by_user_ids(user_ids, db=db)} for thread_message in thread_messages: - message_user = None - if thread_message.user_id not in message_users: - message_user = await Users.get_user_by_id(thread_message.user_id, db=db) - message_users[thread_message.user_id] = message_user - else: - message_user = message_users[thread_message.user_id] + message_user = message_users.get(thread_message.user_id) if thread_message.meta and thread_message.meta.get('model_id', None): # If the message was sent by a model, use the model name diff --git a/backend/open_webui/routers/chats.py b/backend/open_webui/routers/chats.py index 02f9a74662..7cf125f7c7 100644 --- a/backend/open_webui/routers/chats.py +++ b/backend/open_webui/routers/chats.py @@ -978,7 +978,7 @@ async def update_chat_message_by_id( event_emitter = await get_event_emitter( { - 'user_id': user.id, + 'user_id': chat.user_id, 'chat_id': id, 'message_id': message_id, }, @@ -1032,7 +1032,7 @@ async def send_chat_message_event_by_id( event_emitter = await get_event_emitter( { - 'user_id': user.id, + 'user_id': chat.user_id, 'chat_id': id, 'message_id': message_id, } diff --git a/backend/open_webui/routers/configs.py b/backend/open_webui/routers/configs.py index 7c54c09039..68e1d129dc 100644 --- a/backend/open_webui/routers/configs.py +++ b/backend/open_webui/routers/configs.py @@ -6,7 +6,7 @@ import aiohttp from typing import Optional -from open_webui.env import AIOHTTP_CLIENT_TIMEOUT +from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL, AIOHTTP_CLIENT_TIMEOUT from open_webui.utils.auth import get_admin_user, get_verified_user from open_webui.config import get_config, save_config, async_save_config from open_webui.config import BannerModel @@ -293,7 +293,7 @@ async def verify_terminal_server_connection( ) as session: # Orchestrators expose a policies API; plain terminals don't. try: - async with session.get(f'{base_url}/api/v1/policies', headers=headers) as resp: + async with session.get(f'{base_url}/api/v1/policies', headers=headers, ssl=AIOHTTP_CLIENT_SESSION_SSL) as resp: if resp.ok: return {'status': True, 'type': 'orchestrator'} except Exception: @@ -301,7 +301,7 @@ async def verify_terminal_server_connection( # Fall back to open-terminal config endpoint. try: - async with session.get(f'{base_url}/api/config', headers=headers) as resp: + async with session.get(f'{base_url}/api/config', headers=headers, ssl=AIOHTTP_CLIENT_SESSION_SSL) as resp: if resp.ok: return {'status': True, 'type': 'terminal'} except Exception: @@ -342,7 +342,7 @@ async def put_terminal_server_policy( timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT), ) as session: policy_url = f'{base_url}/api/v1/policies/{form_data.policy_id}' - async with session.put(policy_url, headers=headers, json=form_data.policy_data) as resp: + async with session.put(policy_url, headers=headers, json=form_data.policy_data, ssl=AIOHTTP_CLIENT_SESSION_SSL) as resp: if resp.ok: return await resp.json() detail = await resp.text() @@ -369,7 +369,7 @@ async def verify_tool_servers_config(request: Request, form_data: ToolServerConn trust_env=True, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT), ) as session: - async with session.get(discovery_url) as oauth_server_metadata_response: + async with session.get(discovery_url, ssl=AIOHTTP_CLIENT_SESSION_SSL) as oauth_server_metadata_response: if oauth_server_metadata_response.status == 200: try: oauth_server_metadata = OAuthMetadata.model_validate( diff --git a/backend/open_webui/routers/functions.py b/backend/open_webui/routers/functions.py index 1d0f0342d2..baec1f0870 100644 --- a/backend/open_webui/routers/functions.py +++ b/backend/open_webui/routers/functions.py @@ -6,7 +6,7 @@ import aiohttp from pathlib import Path from typing import Optional -from open_webui.env import AIOHTTP_CLIENT_TIMEOUT +from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL, AIOHTTP_CLIENT_TIMEOUT from open_webui.models.functions import ( FunctionForm, FunctionModel, @@ -117,7 +117,7 @@ async def load_function_from_url(request: Request, form_data: LoadUrlForm, user= async with aiohttp.ClientSession( trust_env=True, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT) ) as session: - async with session.get(url, headers={'Content-Type': 'application/json'}) as resp: + async with session.get(url, headers={'Content-Type': 'application/json'}, ssl=AIOHTTP_CLIENT_SESSION_SSL) as resp: if resp.status != 200: raise HTTPException(status_code=resp.status, detail='Failed to fetch the function') data = await resp.text() diff --git a/backend/open_webui/routers/knowledge.py b/backend/open_webui/routers/knowledge.py index d8d92b2428..f503169fc0 100644 --- a/backend/open_webui/routers/knowledge.py +++ b/backend/open_webui/routers/knowledge.py @@ -539,9 +539,7 @@ async def update_knowledge_access_by_id( 'sharing.public_knowledge', ) - knowledge.access_grants = await AccessGrants.set_access_grants( - 'knowledge', id, form_data.access_grants, db=db - ) + knowledge.access_grants = await AccessGrants.set_access_grants('knowledge', id, form_data.access_grants, db=db) return KnowledgeFilesResponse( **knowledge.model_dump(), diff --git a/backend/open_webui/routers/openai.py b/backend/open_webui/routers/openai.py index 82c844afba..8a7c3aca72 100644 --- a/backend/open_webui/routers/openai.py +++ b/backend/open_webui/routers/openai.py @@ -1296,6 +1296,7 @@ async def embeddings(request: Request, form_data: dict, user): headers=headers, cookies=cookies, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT), + ssl=AIOHTTP_CLIENT_SESSION_SSL, ) if 'text/event-stream' in r.headers.get('Content-Type', ''): diff --git a/backend/open_webui/routers/pipelines.py b/backend/open_webui/routers/pipelines.py index 94c1357fd7..580fb42fb2 100644 --- a/backend/open_webui/routers/pipelines.py +++ b/backend/open_webui/routers/pipelines.py @@ -94,9 +94,24 @@ async def process_pipeline_inlet_filter(request, payload, user, models): response.raise_for_status() payload = await response.json() except aiohttp.ClientResponseError as e: - res = await response.json() if response.content_type == 'application/json' else {} - if 'detail' in res: - raise Exception(response.status, res['detail']) + try: + res = await response.json() if 'application/json' in response.content_type else {} + if 'detail' in res: + raise HTTPException( + status_code=response.status, + detail=res['detail'], + ) + except HTTPException: + raise + except Exception: + pass + + raise HTTPException( + status_code=response.status, + detail=e.message, + ) + except HTTPException: + raise except Exception as e: log.exception(f'Connection error: {e}') @@ -146,9 +161,21 @@ async def process_pipeline_outlet_filter(request, payload, user, models): try: res = await response.json() if 'application/json' in response.content_type else {} if 'detail' in res: - raise Exception(response.status, res) + raise HTTPException( + status_code=response.status, + detail=res['detail'], + ) + except HTTPException: + raise except Exception: pass + + raise HTTPException( + status_code=response.status, + detail=e.message, + ) + except HTTPException: + raise except Exception as e: log.exception(f'Connection error: {e}') diff --git a/backend/open_webui/routers/terminals.py b/backend/open_webui/routers/terminals.py index 0d607d1f78..003db06968 100644 --- a/backend/open_webui/routers/terminals.py +++ b/backend/open_webui/routers/terminals.py @@ -16,6 +16,7 @@ from starlette.background import BackgroundTask from open_webui.utils.auth import get_verified_user from open_webui.utils.access_control import has_connection_access +from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL from open_webui.models.groups import Groups from open_webui.models.users import Users @@ -141,6 +142,7 @@ async def proxy_terminal( headers=headers, cookies=cookies, data=body or None, + ssl=AIOHTTP_CLIENT_SESSION_SSL, ) upstream_content_type = upstream_response.headers.get('content-type', '') @@ -279,7 +281,7 @@ async def ws_terminal( session = aiohttp.ClientSession() try: - async with session.ws_connect(upstream_url) as upstream: + async with session.ws_connect(upstream_url, ssl=AIOHTTP_CLIENT_SESSION_SSL) as upstream: import asyncio import json as _json diff --git a/backend/open_webui/routers/tools.py b/backend/open_webui/routers/tools.py index d70b4038fe..4c3e77e566 100644 --- a/backend/open_webui/routers/tools.py +++ b/backend/open_webui/routers/tools.py @@ -4,7 +4,7 @@ from typing import Optional import time import re import aiohttp -from open_webui.env import AIOHTTP_CLIENT_TIMEOUT +from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL, AIOHTTP_CLIENT_TIMEOUT from open_webui.models.groups import Groups from pydantic import BaseModel, HttpUrl from fastapi import APIRouter, Depends, HTTPException, Request, status @@ -274,7 +274,7 @@ async def load_tool_from_url(request: Request, form_data: LoadUrlForm, user=Depe async with aiohttp.ClientSession( trust_env=True, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT) ) as session: - async with session.get(url, headers={'Content-Type': 'application/json'}) as resp: + async with session.get(url, headers={'Content-Type': 'application/json'}, ssl=AIOHTTP_CLIENT_SESSION_SSL) as resp: if resp.status != 200: raise HTTPException(status_code=resp.status, detail='Failed to fetch the tool') data = await resp.text() diff --git a/backend/open_webui/routers/users.py b/backend/open_webui/routers/users.py index d8bfcefac8..9dec855e45 100644 --- a/backend/open_webui/routers/users.py +++ b/backend/open_webui/routers/users.py @@ -14,7 +14,7 @@ from open_webui.models.auths import Auths from open_webui.models.oauth_sessions import OAuthSessions from open_webui.models.groups import Groups -from open_webui.models.chats import Chats + from open_webui.models.users import ( UserModel, UserGroupIdsModel, @@ -414,18 +414,6 @@ class UserActiveResponse(UserStatus): @router.get('/{user_id}', response_model=UserActiveResponse) async def get_user_by_id(user_id: str, user=Depends(get_admin_user), db: AsyncSession = Depends(get_async_session)): - # Check if user_id is a shared chat - # If it is, get the user_id from the chat - if user_id.startswith('shared-'): - chat_id = user_id.replace('shared-', '') - chat = await Chats.get_chat_by_id(chat_id) - if chat: - user_id = chat.user_id - else: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.USER_NOT_FOUND, - ) user = await Users.get_user_by_id(user_id, db=db) if user: diff --git a/backend/open_webui/static/favicon.ico b/backend/open_webui/static/favicon.ico index 14c5f9c6d4..b819d42f96 100644 Binary files a/backend/open_webui/static/favicon.ico and b/backend/open_webui/static/favicon.ico differ diff --git a/backend/open_webui/static/favicon.png b/backend/open_webui/static/favicon.png index 63735ad461..10c84f440c 100644 Binary files a/backend/open_webui/static/favicon.png and b/backend/open_webui/static/favicon.png differ diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index 508e7d8b8f..9c1a91abc3 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -56,19 +56,30 @@ async def get_current_timestamp( """ Get the current Unix timestamp in seconds. - :return: JSON with current_timestamp (seconds) and current_iso (ISO format) + :return: JSON with current_timestamp (seconds), current_iso (UTC ISO format), and user_local_iso (user's local time) """ try: import datetime + from zoneinfo import ZoneInfo now = datetime.datetime.now(datetime.timezone.utc) - return json.dumps( - { - 'current_timestamp': int(now.timestamp()), - 'current_iso': now.isoformat(), - }, - ensure_ascii=False, - ) + result = { + 'current_timestamp': int(now.timestamp()), + 'current_iso': now.isoformat(), + } + + # Include the user's local time if timezone is available + tz_name = __user__.get('timezone') if __user__ else None + if tz_name: + try: + user_tz = ZoneInfo(tz_name) + user_now = now.astimezone(user_tz) + result['user_local_iso'] = user_now.isoformat() + result['user_timezone'] = tz_name + except Exception: + pass + + return json.dumps(result, ensure_ascii=False) except Exception as e: log.exception(f'get_current_timestamp error: {e}') return json.dumps({'error': str(e)}) @@ -110,15 +121,27 @@ async def calculate_timestamp( adjusted_ts = int(adjusted.timestamp()) - return json.dumps( - { - 'current_timestamp': current_ts, - 'current_iso': now.isoformat(), - 'calculated_timestamp': adjusted_ts, - 'calculated_iso': adjusted.isoformat(), - }, - ensure_ascii=False, - ) + result = { + 'current_timestamp': current_ts, + 'current_iso': now.isoformat(), + 'calculated_timestamp': adjusted_ts, + 'calculated_iso': adjusted.isoformat(), + } + + # Include the user's local time if timezone is available + tz_name = __user__.get('timezone') if __user__ else None + if tz_name: + try: + from zoneinfo import ZoneInfo + + user_tz = ZoneInfo(tz_name) + result['user_local_iso'] = now.astimezone(user_tz).isoformat() + result['calculated_local_iso'] = adjusted.astimezone(user_tz).isoformat() + result['user_timezone'] = tz_name + except Exception: + pass + + return json.dumps(result, ensure_ascii=False) except ImportError: # Fallback without dateutil import datetime @@ -128,15 +151,26 @@ async def calculate_timestamp( total_days = days_ago + (weeks_ago * 7) + (months_ago * 30) + (years_ago * 365) adjusted = now - datetime.timedelta(days=total_days) adjusted_ts = int(adjusted.timestamp()) - return json.dumps( - { - 'current_timestamp': current_ts, - 'current_iso': now.isoformat(), - 'calculated_timestamp': adjusted_ts, - 'calculated_iso': adjusted.isoformat(), - }, - ensure_ascii=False, - ) + result = { + 'current_timestamp': current_ts, + 'current_iso': now.isoformat(), + 'calculated_timestamp': adjusted_ts, + 'calculated_iso': adjusted.isoformat(), + } + + tz_name = __user__.get('timezone') if __user__ else None + if tz_name: + try: + from zoneinfo import ZoneInfo + + user_tz = ZoneInfo(tz_name) + result['user_local_iso'] = now.astimezone(user_tz).isoformat() + result['calculated_local_iso'] = adjusted.astimezone(user_tz).isoformat() + result['user_timezone'] = tz_name + except Exception: + pass + + return json.dumps(result, ensure_ascii=False) except Exception as e: log.exception(f'calculate_timestamp error: {e}') return json.dumps({'error': str(e)}) @@ -2810,3 +2844,424 @@ async def delete_automation( except Exception as e: log.exception(f'delete_automation error: {e}') return json.dumps({'error': str(e)}) + + +# ============================================================================= +# CALENDAR TOOLS +# ============================================================================= + + +def _get_user_tz(user_dict: dict): + """Get the user's timezone as a ZoneInfo, falling back to UTC.""" + from zoneinfo import ZoneInfo + + tz_name = None + if user_dict: + tz_name = user_dict.get('timezone') + if tz_name: + try: + return ZoneInfo(tz_name) + except Exception: + pass + return ZoneInfo('UTC') + + +def _dt_to_ns(dt_str: str, tz) -> int: + """Convert a datetime string to nanoseconds since epoch, interpreting in the given timezone.""" + from datetime import datetime + + dt = datetime.fromisoformat(dt_str) + # If naive (no timezone info), localize to user's timezone + if dt.tzinfo is None: + dt = dt.replace(tzinfo=tz) + return int(dt.timestamp() * 1_000) * 1_000_000 + + +def _ns_to_dt(ns: int, tz) -> str: + """Convert nanoseconds since epoch to a datetime string in the given timezone.""" + from datetime import datetime + + seconds = ns / 1_000_000_000 + dt = datetime.fromtimestamp(seconds, tz=tz) + return dt.strftime('%Y-%m-%d %H:%M') + + +def _event_to_dict(event, tz) -> dict: + """Convert a calendar event model to a human-friendly dict with local timestamps.""" + return { + 'id': event.id, + 'calendar_id': event.calendar_id, + 'title': event.title, + 'description': event.description or '', + 'start': _ns_to_dt(event.start_at, tz), + 'end': _ns_to_dt(event.end_at, tz) if event.end_at else None, + 'all_day': event.all_day, + 'location': event.location or '', + 'color': event.color, + 'is_cancelled': event.is_cancelled, + } + + +async def search_calendar_events( + query: Optional[str] = None, + start: Optional[str] = None, + end: Optional[str] = None, + count: int = 10, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Search calendar events by text and/or date range. + Returns matching events across all accessible calendars. + + :param query: Search text to match against event title, description, or location (optional) + :param start: Only return events starting at or after this datetime, e.g. "2026-04-20 00:00" (optional) + :param end: Only return events starting before this datetime, e.g. "2026-04-27 00:00" (optional) + :param count: Maximum number of events to return (default: 10) + :return: JSON list of matching events with id, title, description, start, end, calendar_id, location + """ + if __request__ is None: + return json.dumps({'error': 'Request context not available'}) + + if not __user__: + return json.dumps({'error': 'User context not available'}) + + try: + from open_webui.models.calendar import CalendarEvents + + user_id = __user__.get('id') + tz = _get_user_tz(__user__) + + if isinstance(count, str): + try: + count = int(count) + except ValueError: + count = 10 + + if start or end: + # Date range query — use get_events_by_range + try: + start_ns = _dt_to_ns(start, tz) if start else 0 + except (ValueError, TypeError) as e: + return json.dumps({'error': f'Invalid start datetime: {e}'}) + + try: + end_ns = ( + _dt_to_ns(end, tz) + if end + else int(time.time() * 1_000) * 1_000_000 + 365 * 86400 * 1_000_000_000_000 + ) + except (ValueError, TypeError) as e: + return json.dumps({'error': f'Invalid end datetime: {e}'}) + + items = await CalendarEvents.get_events_by_range( + user_id=user_id, + start=start_ns, + end=end_ns, + ) + + # Apply text filter if query is also provided + if query: + q = query.lower() + items = [ + e + for e in items + if q in (e.title or '').lower() + or q in (e.description or '').lower() + or q in (e.location or '').lower() + ] + + events = [_event_to_dict(item, tz) for item in items[:count]] + return json.dumps( + {'events': events, 'total': len(items)}, + ensure_ascii=False, + ) + else: + # Text-only search + result = await CalendarEvents.search_events( + user_id=user_id, + query=query, + skip=0, + limit=count, + ) + + events = [_event_to_dict(item, tz) for item in result.items] + return json.dumps( + {'events': events, 'total': result.total}, + ensure_ascii=False, + ) + except Exception as e: + log.exception(f'search_calendar_events error: {e}') + return json.dumps({'error': str(e)}) + + +async def create_calendar_event( + title: str, + start: str, + end: Optional[str] = None, + description: Optional[str] = None, + calendar_id: Optional[str] = None, + all_day: bool = False, + location: Optional[str] = None, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Create a new calendar event. If no calendar_id is provided, the event is + added to the user's default calendar. + + :param title: Event title + :param start: Start datetime string in your local time (e.g. "2026-04-20 09:00" or "2026-04-20T09:00:00") + :param end: End datetime string in your local time (optional, omit for point-in-time events) + :param description: Event description (optional) + :param calendar_id: Target calendar ID (optional, uses default calendar if omitted) + :param all_day: Whether this is an all-day event (default: false) + :param location: Event location (optional) + :return: JSON with the created event details including id + """ + if __request__ is None: + return json.dumps({'error': 'Request context not available'}) + + if not __user__: + return json.dumps({'error': 'User context not available'}) + + try: + from open_webui.models.calendar import Calendars, CalendarEvents, CalendarEventForm + + user_id = __user__.get('id') + + # Resolve calendar_id: use provided, or fall back to default + if not calendar_id: + calendars = await Calendars.get_calendars_by_user(user_id) + default_cal = next((c for c in calendars if c.is_default), None) + if not default_cal and calendars: + default_cal = calendars[0] + if not default_cal: + return json.dumps({'error': 'No calendars found. Cannot create event.'}) + calendar_id = default_cal.id + + # Verify access + cal = await Calendars.get_calendar_by_id(calendar_id) + if not cal: + return json.dumps({'error': 'Calendar not found'}) + if cal.user_id != user_id and __user__.get('role') != 'admin': + from open_webui.models.access_grants import AccessGrants + from open_webui.models.groups import Groups + + user_group_ids = [g.id for g in await Groups.get_groups_by_member_id(user_id)] + if not await AccessGrants.has_access( + user_id=user_id, + resource_type='calendar', + resource_id=cal.id, + permission='write', + user_group_ids=set(user_group_ids), + ): + return json.dumps({'error': 'Access denied to this calendar'}) + + # Coerce boolean from LLM + if isinstance(all_day, str): + all_day = all_day.lower() in ('true', '1', 'yes') + + # Convert datetime strings to nanoseconds using user's timezone + tz = _get_user_tz(__user__) + try: + start_ns = _dt_to_ns(start, tz) + except (ValueError, TypeError) as e: + return json.dumps({'error': f'Invalid start datetime: {e}. Use format like "2026-04-20 09:00"'}) + + end_ns = None + if end: + try: + end_ns = _dt_to_ns(end, tz) + except (ValueError, TypeError) as e: + return json.dumps({'error': f'Invalid end datetime: {e}. Use format like "2026-04-20 10:00"'}) + elif not all_day: + # Default to 1 hour duration + end_ns = start_ns + 3_600_000_000_000 + + form = CalendarEventForm( + calendar_id=calendar_id, + title=title, + description=description, + start_at=start_ns, + end_at=end_ns, + all_day=all_day, + location=location, + ) + + event = await CalendarEvents.insert_new_event(user_id, form) + if not event: + return json.dumps({'error': 'Failed to create event'}) + + return json.dumps( + { + 'status': 'success', + **_event_to_dict(event, tz), + }, + ensure_ascii=False, + ) + except Exception as e: + log.exception(f'create_calendar_event error: {e}') + return json.dumps({'error': str(e)}) + + +async def update_calendar_event( + event_id: str, + title: Optional[str] = None, + description: Optional[str] = None, + start: Optional[str] = None, + end: Optional[str] = None, + all_day: Optional[bool] = None, + location: Optional[str] = None, + is_cancelled: Optional[bool] = None, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Update an existing calendar event. Only provided fields are changed; + omitted fields stay the same. + + :param event_id: The ID of the event to update + :param title: New event title (optional) + :param description: New event description (optional) + :param start: New start datetime string in your local time, e.g. "2026-04-20 09:00" (optional) + :param end: New end datetime string in your local time (optional) + :param all_day: Whether this is an all-day event (optional) + :param location: New event location (optional) + :param is_cancelled: Set to true to cancel the event (optional) + :return: JSON with the updated event details + """ + if __request__ is None: + return json.dumps({'error': 'Request context not available'}) + + if not __user__: + return json.dumps({'error': 'User context not available'}) + + try: + from open_webui.models.calendar import Calendars, CalendarEvents, CalendarEventUpdateForm + from open_webui.models.access_grants import AccessGrants + from open_webui.models.groups import Groups + + user_id = __user__.get('id') + + event = await CalendarEvents.get_event_by_id(event_id) + if not event: + return json.dumps({'error': 'Event not found'}) + + # Check write access to the event's calendar + cal = await Calendars.get_calendar_by_id(event.calendar_id) + if cal and cal.user_id != user_id and __user__.get('role') != 'admin': + user_group_ids = [g.id for g in await Groups.get_groups_by_member_id(user_id)] + if not await AccessGrants.has_access( + user_id=user_id, + resource_type='calendar', + resource_id=cal.id, + permission='write', + user_group_ids=set(user_group_ids), + ): + return json.dumps({'error': 'Access denied'}) + + # Coerce boolean strings from LLM + if isinstance(all_day, str): + all_day = all_day.lower() in ('true', '1', 'yes') + if isinstance(is_cancelled, str): + is_cancelled = is_cancelled.lower() in ('true', '1', 'yes') + + # Convert datetime strings to nanoseconds using user's timezone + tz = _get_user_tz(__user__) + start_ns = None + if start is not None: + try: + start_ns = _dt_to_ns(start, tz) + except (ValueError, TypeError) as e: + return json.dumps({'error': f'Invalid start datetime: {e}'}) + + end_ns = None + if end is not None: + try: + end_ns = _dt_to_ns(end, tz) + except (ValueError, TypeError) as e: + return json.dumps({'error': f'Invalid end datetime: {e}'}) + + form = CalendarEventUpdateForm( + title=title, + description=description, + start_at=start_ns, + end_at=end_ns, + all_day=all_day, + location=location, + is_cancelled=is_cancelled, + ) + + updated = await CalendarEvents.update_event_by_id(event_id, form) + if not updated: + return json.dumps({'error': 'Failed to update event'}) + + return json.dumps( + { + 'status': 'success', + **_event_to_dict(updated, tz), + }, + ensure_ascii=False, + ) + except Exception as e: + log.exception(f'update_calendar_event error: {e}') + return json.dumps({'error': str(e)}) + + +async def delete_calendar_event( + event_id: str, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Delete a calendar event permanently. + + :param event_id: The ID of the event to delete + :return: JSON confirming the event was deleted + """ + if __request__ is None: + return json.dumps({'error': 'Request context not available'}) + + if not __user__: + return json.dumps({'error': 'User context not available'}) + + try: + from open_webui.models.calendar import Calendars, CalendarEvents + from open_webui.models.access_grants import AccessGrants + from open_webui.models.groups import Groups + + user_id = __user__.get('id') + + event = await CalendarEvents.get_event_by_id(event_id) + if not event: + return json.dumps({'error': 'Event not found'}) + + # Check write access + cal = await Calendars.get_calendar_by_id(event.calendar_id) + if cal and cal.user_id != user_id and __user__.get('role') != 'admin': + user_group_ids = [g.id for g in await Groups.get_groups_by_member_id(user_id)] + if not await AccessGrants.has_access( + user_id=user_id, + resource_type='calendar', + resource_id=cal.id, + permission='write', + user_group_ids=set(user_group_ids), + ): + return json.dumps({'error': 'Access denied'}) + + title = event.title + result = await CalendarEvents.delete_event_by_id(event_id) + if not result: + return json.dumps({'error': 'Failed to delete event'}) + + return json.dumps( + { + 'status': 'success', + 'message': f'Event "{title}" deleted', + }, + ensure_ascii=False, + ) + except Exception as e: + log.exception(f'delete_calendar_event error: {e}') + return json.dumps({'error': str(e)}) diff --git a/backend/open_webui/utils/automations.py b/backend/open_webui/utils/automations.py index 3866eb865a..0c6e4e969a 100644 --- a/backend/open_webui/utils/automations.py +++ b/backend/open_webui/utils/automations.py @@ -1,11 +1,16 @@ """ -Automation utilities. +Automation utilities and unified scheduler. -RRULE helpers, worker loop, and execution logic. +RRULE helpers, scheduler worker loop, and execution logic. Follows the utils/.py pattern (cf. utils/channels.py, utils/task.py). +The scheduler_worker_loop handles all time-based background work: + - Automation execution (claim_due → execute) + - Calendar event alerts (upcoming events → socket + webhook notifications) + Environment: - AUTOMATION_POLL_INTERVAL – seconds between polls (default: 10) + SCHEDULER_POLL_INTERVAL – seconds between polls (default: 10) + CALENDAR_ALERT_LOOKAHEAD_MINUTES – default alert window (default: 5) """ import asyncio @@ -31,7 +36,8 @@ from open_webui.internal.db import get_async_db log = logging.getLogger(__name__) -AUTOMATION_POLL_INTERVAL = int(os.getenv('AUTOMATION_POLL_INTERVAL', '10')) +SCHEDULER_POLL_INTERVAL = int(os.getenv('SCHEDULER_POLL_INTERVAL', os.getenv('AUTOMATION_POLL_INTERVAL', '10'))) +CALENDAR_ALERT_LOOKAHEAD_MINUTES = int(os.getenv('CALENDAR_ALERT_LOOKAHEAD_MINUTES', '10')) #################### @@ -117,26 +123,49 @@ def rrule_interval_seconds(s: str) -> Optional[int]: ############################ +# Keep the old name as an alias so any stale imports still work. async def automation_worker_loop(app) -> None: - """Poll for due automations, claim, fire-and-forget execute. + """Deprecated alias — use scheduler_worker_loop.""" + await scheduler_worker_loop(app) + + +async def scheduler_worker_loop(app) -> None: + """Unified background scheduler for all time-based work. + + Handles: + 1. Automation execution (ENABLE_AUTOMATIONS) + 2. Calendar event alerts (ENABLE_CALENDAR) Runs on every instance. Poll interval is configurable via - AUTOMATION_POLL_INTERVAL env var (default: 10 seconds). + SCHEDULER_POLL_INTERVAL env var (default: 10 seconds). """ - log.info(f'Automation worker started (poll interval: {AUTOMATION_POLL_INTERVAL}s)') + log.info(f'Scheduler worker started (poll interval: {SCHEDULER_POLL_INTERVAL}s)') while True: try: - async with get_async_db() as db: - batch = await Automations.claim_due(int(time.time_ns()), limit=10, db=db) - if batch: - log.info(f'Claimed {len(batch)} due automation(s)') - for automation in batch: - asyncio.create_task(execute_automation(app, automation)) + # ── Automations ── + if getattr(app.state.config, 'ENABLE_AUTOMATIONS', False): + try: + async with get_async_db() as db: + batch = await Automations.claim_due(int(time.time_ns()), limit=10, db=db) + if batch: + log.info(f'Claimed {len(batch)} due automation(s)') + for automation in batch: + asyncio.create_task(execute_automation(app, automation)) + except Exception: + log.exception('Scheduler: automation error') + + # ── Calendar Alerts ── + if getattr(app.state.config, 'ENABLE_CALENDAR', False): + try: + await _check_calendar_alerts(app) + except Exception: + log.exception('Scheduler: calendar alert error') + except Exception: - log.exception('Automation worker error') + log.exception('Scheduler worker error') # Jitter to spread load across instances - await asyncio.sleep(AUTOMATION_POLL_INTERVAL + random.uniform(0, 2)) + await asyncio.sleep(SCHEDULER_POLL_INTERVAL + random.uniform(0, 2)) ########################## @@ -243,6 +272,7 @@ async def _set_terminal_cwd(app, server_id: str, user, cwd: str, chat_id: str) - handled correctly — same path the frontend uses. """ import aiohttp + from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL connections = getattr(getattr(app, 'state', None), 'config', None) if connections is None: @@ -278,6 +308,7 @@ async def _set_terminal_cwd(app, server_id: str, user, cwd: str, chat_id: str) - target_url, json={'path': cwd}, headers=headers, + ssl=AIOHTTP_CLIENT_SESSION_SSL, ) as resp: if resp.status != 200: body = await resp.text() @@ -429,6 +460,98 @@ async def execute_automation(app, automation: AutomationModel) -> None: #################### +async def _check_calendar_alerts(app) -> None: + """Check for upcoming calendar events and send alert notifications. + + De-duplication is DB-backed via meta.alerted_at — survives restarts + and works across multiple instances. + """ + from open_webui.models.calendar import CalendarEvents, CalendarEventUpdateForm + from open_webui.socket.main import sio + + now_ns = int(time.time_ns()) + default_lookahead_ns = CALENDAR_ALERT_LOOKAHEAD_MINUTES * 60 * 1_000_000_000 + + async with get_async_db() as db: + upcoming = await CalendarEvents.get_upcoming_events(now_ns, default_lookahead_ns, db=db) + + if not upcoming: + return + + for event, user_tz in upcoming: + # Skip if already alerted for this start time + if event.meta and event.meta.get('alerted_at'): + continue + + # Compute minutes until event starts + minutes_until = max(0, int((event.start_at - now_ns) / (60 * 1_000_000_000))) + + alert_data = { + 'event_id': event.id, + 'title': event.title, + 'description': event.description or '', + 'start_at': event.start_at, + 'minutes_until': minutes_until, + 'calendar_id': event.calendar_id, + 'location': event.location or '', + } + + await sio.emit( + 'events', + { + 'data': { + 'type': 'calendar:alert', + 'data': alert_data, + }, + }, + room=f'user:{event.user_id}', + ) + + # Mark as alerted in DB so it survives restarts / multi-instance + try: + await CalendarEvents.update_event_by_id( + event.id, + CalendarEventUpdateForm(meta={'alerted_at': now_ns}), + ) + except Exception: + log.debug(f'Failed to mark event {event.id} as alerted', exc_info=True) + + # Send webhook notification if user has one configured + try: + webui_name = getattr(app.state, 'WEBUI_NAME', 'Open WebUI') + enable_user_webhooks = getattr(app.state.config, 'ENABLE_USER_WEBHOOKS', False) + + if enable_user_webhooks: + user = await Users.get_user_by_id(event.user_id) + if user and user.settings: + webhook_url = ( + user.settings.get('ui', {}).get('notifications', {}).get('webhook_url', None) + if isinstance(user.settings, dict) + else getattr(getattr(user.settings, 'ui', None), 'get', lambda *a: None)( + 'notifications', {} + ).get('webhook_url', None) + if hasattr(user.settings, 'ui') + else None + ) + if webhook_url: + from open_webui.utils.webhook import post_webhook + + time_str = f'in {minutes_until} min' if minutes_until > 0 else 'now' + await post_webhook( + webui_name, + webhook_url, + f'{event.title} — starting {time_str}', + { + 'action': 'calendar_alert', + 'title': event.title, + 'minutes_until': minutes_until, + 'event_id': event.id, + }, + ) + except Exception: + log.debug(f'Failed to send webhook for calendar alert {event.id}', exc_info=True) + + async def _record_run( automation_id: str, status: str, diff --git a/backend/open_webui/utils/calendar.py b/backend/open_webui/utils/calendar.py new file mode 100644 index 0000000000..9484c58dc0 --- /dev/null +++ b/backend/open_webui/utils/calendar.py @@ -0,0 +1,83 @@ +""" +Calendar utilities. + +RRULE expansion reusing the automation infra. +""" + +import logging +from datetime import datetime, timedelta +from typing import Optional +from zoneinfo import ZoneInfo + +from open_webui.utils.automations import _parse_rule + +log = logging.getLogger(__name__) + + +def expand_recurring_event( + event_dict: dict, + range_start_ns: int, + range_end_ns: int, + tz: Optional[str] = None, + max_instances: int = 5000, +) -> list[dict]: + """Expand a recurring event into individual instances within a date range. + + Takes an event dict (from CalendarEventModel.model_dump()) and produces + one dict per occurrence, with adjusted start_at / end_at. + """ + from dateutil.rrule import rrulestr + + rrule_str = event_dict.get('rrule') + if not rrule_str: + return [event_dict] + + range_start_dt = datetime.fromtimestamp(range_start_ns / 1_000_000_000) + range_end_dt = datetime.fromtimestamp(range_end_ns / 1_000_000_000) + scan_start = range_start_dt - timedelta(days=1) + + try: + # Parse with dtstart near the range so we never iterate from epoch + rule = rrulestr(rrule_str, dtstart=scan_start, ignoretz=True) + except Exception: + log.warning(f'Failed to parse RRULE for event {event_dict.get("id")}: {rrule_str}') + return [event_dict] + + original_start_ns = event_dict['start_at'] + original_end_ns = event_dict.get('end_at') + duration_ns = (original_end_ns - original_start_ns) if original_end_ns else None + + instances = [] + dt = rule.after(scan_start, inc=True) + + while dt and dt < range_end_dt and len(instances) < max_instances: + if tz: + try: + dt_tz = dt.replace(tzinfo=ZoneInfo(tz)) + instance_start_ns = int(dt_tz.timestamp() * 1_000_000_000) + except Exception: + instance_start_ns = int(dt.timestamp() * 1_000_000_000) + else: + instance_start_ns = int(dt.timestamp() * 1_000_000_000) + + if instance_start_ns >= range_start_ns: + instance = { + **event_dict, + 'start_at': instance_start_ns, + 'end_at': (instance_start_ns + duration_ns) if duration_ns else None, + 'instance_id': f'{event_dict["id"]}_{instance_start_ns}', + } + instances.append(instance) + + dt = rule.after(dt) + + return instances + + +def ns_from_date(year: int, month: int, day: int, tz: Optional[str] = None) -> int: + """Create epoch nanoseconds from a date.""" + if tz: + dt = datetime(year, month, day, tzinfo=ZoneInfo(tz)) + else: + dt = datetime(year, month, day) + return int(dt.timestamp() * 1_000_000_000) diff --git a/backend/open_webui/utils/chat.py b/backend/open_webui/utils/chat.py index 3539d57c86..9899469da9 100644 --- a/backend/open_webui/utils/chat.py +++ b/backend/open_webui/utils/chat.py @@ -10,7 +10,7 @@ import json import uuid import asyncio -from fastapi import Request, status +from fastapi import HTTPException, Request, status from starlette.responses import Response, StreamingResponse, JSONResponse @@ -328,6 +328,8 @@ async def chat_completed(request: Request, form_data: dict, user: Any): try: data = await process_pipeline_outlet_filter(request, data, user, models) + except HTTPException: + raise except Exception as e: raise Exception(f'Error: {e}') diff --git a/backend/open_webui/utils/files.py b/backend/open_webui/utils/files.py index 78392f2d41..7d0d9da2c2 100644 --- a/backend/open_webui/utils/files.py +++ b/backend/open_webui/utils/files.py @@ -26,12 +26,29 @@ import base64 import io import re -from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL +from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL, ENABLE_IMAGE_CONTENT_TYPE_EXTENSION_FALLBACK from open_webui.utils.session_pool import get_session BASE64_IMAGE_URL_PREFIX = re.compile(r'data:image/\w+;base64,', re.IGNORECASE) MARKDOWN_IMAGE_URL_PATTERN = re.compile(r'!\[(.*?)\]\((.+?)\)', re.IGNORECASE) +# Extension-based MIME fallback, only used when ENABLE_IMAGE_CONTENT_TYPE_EXTENSION_FALLBACK is True. +_IMAGE_MIME_FALLBACK = { + ".webp": "image/webp", + ".png": "image/png", + ".jpg": "image/jpeg", + ".jpeg": "image/jpeg", + ".gif": "image/gif", + ".svg": "image/svg+xml", + ".bmp": "image/bmp", + ".tiff": "image/tiff", + ".tif": "image/tiff", + ".ico": "image/x-icon", + ".heic": "image/heic", + ".heif": "image/heif", + ".avif": "image/avif", +} + async def get_image_base64_from_url(url: str) -> Optional[str]: try: @@ -58,7 +75,14 @@ async def get_image_base64_from_url(url: str) -> Optional[str]: if file_path.is_file(): with open(file_path, 'rb') as image_file: encoded_string = base64.b64encode(image_file.read()).decode('utf-8') - content_type, _ = mimetypes.guess_type(file_path.name) + content_type = ( + mimetypes.guess_type(file_path.name)[0] + or (file.meta or {}).get('content_type') + ) + if not content_type and ENABLE_IMAGE_CONTENT_TYPE_EXTENSION_FALLBACK: + content_type = _IMAGE_MIME_FALLBACK.get(file_path.suffix.lower()) + if not content_type: + return None return f'data:{content_type};base64,{encoded_string}' else: return None @@ -178,11 +202,16 @@ async def get_image_base64_from_file_id(id: str) -> Optional[str]: # Check if the file already exists in the cache if file_path.is_file(): - import base64 - with open(file_path, 'rb') as image_file: encoded_string = base64.b64encode(image_file.read()).decode('utf-8') - content_type, _ = mimetypes.guess_type(file_path.name) + content_type = ( + mimetypes.guess_type(file_path.name)[0] + or (file.meta or {}).get('content_type') + ) + if not content_type and ENABLE_IMAGE_CONTENT_TYPE_EXTENSION_FALLBACK: + content_type = _IMAGE_MIME_FALLBACK.get(file_path.suffix.lower()) + if not content_type: + return None return f'data:{content_type};base64,{encoded_string}' else: return None diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index d44112b4ec..036dc9bf39 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -427,7 +427,11 @@ def _render_openai_tool_call_handler(item: dict, done: bool) -> str: if atype == 'search': queries = action.get('queries') or [] query = action.get('query', '') - summary = f'Search: {", ".join(str(q) for q in queries)}' if queries else (f'Search: {query}' if query else '') + summary = ( + f'Search: {", ".join(str(q) for q in queries)}' + if queries + else (f'Search: {query}' if query else '') + ) elif atype == 'open_page': summary = f'Open page: {action.get("url", "")}' if action.get('url') else '' elif atype == 'find_in_page': @@ -490,9 +494,13 @@ def serialize_output(output: list) -> str: files = result_item.get('files') embeds = result_item.get('embeds', '') - parts.append(f'
\nTool Executed\n{html.escape(json.dumps(result_text, ensure_ascii=False))}\n
') + parts.append( + f'
\nTool Executed\n{html.escape(json.dumps(result_text, ensure_ascii=False))}\n
' + ) else: - parts.append(f'
\nExecuting...\n
') + parts.append( + f'
\nExecuting...\n
' + ) elif item_type == 'function_call_output': # Already handled inline with function_call above @@ -529,9 +537,13 @@ def serialize_output(output: list) -> str: ) if status == 'completed' or duration is not None or not is_last_item: - parts.append(f'
\nThought for {duration or 0} seconds\n{display}\n
') + parts.append( + f'
\nThought for {duration or 0} seconds\n{display}\n
' + ) else: - parts.append(f'
\nThinking…\n{display}\n
') + parts.append( + f'
\nThinking…\n{display}\n
' + ) elif item_type == 'open_webui:code_interpreter': # Code interpreter needs to inspect/mutate prior accumulated content @@ -570,9 +582,13 @@ def serialize_output(output: list) -> str: output_attr = f' output="{html.escape(output_json)}"' if status == 'completed' or duration is not None or not is_last_item: - parts.append(f'
\nAnalyzed\n{display}\n
') + parts.append( + f'
\nAnalyzed\n{display}\n
' + ) else: - parts.append(f'
\nAnalyzing…\n{display}\n
') + parts.append( + f'
\nAnalyzing…\n{display}\n
' + ) return '\n'.join(parts).strip() diff --git a/backend/open_webui/utils/security_headers.py b/backend/open_webui/utils/security_headers.py index 33956688a1..ecc3b6eb30 100644 --- a/backend/open_webui/utils/security_headers.py +++ b/backend/open_webui/utils/security_headers.py @@ -28,6 +28,10 @@ def set_security_headers() -> Dict[str, str]: - x-frame-options - x-permitted-cross-domain-policies - content-security-policy + - content-security-policy-report-only + - cross-origin-embedder-policy + - cross-origin-opener-policy + - cross-origin-resource-policy - reporting-endpoints Each environment variable is associated with a specific setter function @@ -48,6 +52,10 @@ def set_security_headers() -> Dict[str, str]: 'XFRAME_OPTIONS': set_xframe, 'XPERMITTED_CROSS_DOMAIN_POLICIES': set_xpermitted_cross_domain_policies, 'CONTENT_SECURITY_POLICY': set_content_security_policy, + 'CONTENT_SECURITY_POLICY_REPORT_ONLY': set_content_security_policy_report_only, + 'CROSS_ORIGIN_EMBEDDER_POLICY': set_cross_origin_embedder_policy, + 'CROSS_ORIGIN_OPENER_POLICY': set_cross_origin_opener_policy, + 'CROSS_ORIGIN_RESOURCE_POLICY': set_cross_origin_resource_policy, 'REPORTING_ENDPOINTS': set_reporting_endpoints, } @@ -135,6 +143,38 @@ def set_content_security_policy(value: str): return {'Content-Security-Policy': value} +# Set Content-Security-Policy-Report-Only response header +def set_content_security_policy_report_only(value: str): + return {'Content-Security-Policy-Report-Only': value} + + +# Set Cross-Origin-Embedder-Policy response header +def set_cross_origin_embedder_policy(value: str): + pattern = r'^(unsafe-none|require-corp|credentialless)$' + match = re.match(pattern, value, re.IGNORECASE) + if not match: + value = 'require-corp' + return {'Cross-Origin-Embedder-Policy': value} + + +# Set Cross-Origin-Opener-Policy response header +def set_cross_origin_opener_policy(value: str): + pattern = r'^(unsafe-none|same-origin-allow-popups|same-origin)$' + match = re.match(pattern, value, re.IGNORECASE) + if not match: + value = 'same-origin' + return {'Cross-Origin-Opener-Policy': value} + + +# Set Cross-Origin-Resource-Policy response header +def set_cross_origin_resource_policy(value: str): + pattern = r'^(same-site|same-origin|cross-origin)$' + match = re.match(pattern, value, re.IGNORECASE) + if not match: + value = 'same-origin' + return {'Cross-Origin-Resource-Policy': value} + + # Set Reporting-Endpoints response header def set_reporting_endpoints(value: str): return {'Reporting-Endpoints': value} diff --git a/backend/open_webui/utils/tools.py b/backend/open_webui/utils/tools.py index da817c4741..3f4eac7e91 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -44,6 +44,7 @@ from open_webui.utils.plugin import load_tool_module_by_id from open_webui.utils.access_control import has_access, has_connection_access from open_webui.config import BYPASS_ADMIN_ACCESS_CONTROL from open_webui.env import ( + AIOHTTP_CLIENT_SESSION_SSL, AIOHTTP_CLIENT_TIMEOUT, AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER, AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA, @@ -93,6 +94,10 @@ from open_webui.tools.builtin import ( list_automations, toggle_automation, delete_automation, + search_calendar_events, + create_calendar_event, + update_calendar_event, + delete_calendar_event, ) import copy @@ -547,11 +552,25 @@ async def get_builtin_tools( builtin_functions.extend([create_tasks, update_task]) # Automation tools - create and manage scheduled automations from chat - if is_builtin_tool_enabled('automations') and await has_user_permission('automations'): + if ( + is_builtin_tool_enabled('automations') + and getattr(request.app.state.config, 'ENABLE_AUTOMATIONS', False) + and await has_user_permission('automations') + ): builtin_functions.extend( [create_automation, update_automation, list_automations, toggle_automation, delete_automation] ) + # Calendar tools - search/create/update/delete events + if ( + is_builtin_tool_enabled('calendar') + and getattr(request.app.state.config, 'ENABLE_CALENDAR', False) + and await has_user_permission('calendar') + ): + builtin_functions.extend( + [search_calendar_events, create_calendar_event, update_calendar_event, delete_calendar_event] + ) + for func in builtin_functions: callable = await get_async_tool_function_and_apply_extra_params( func, @@ -889,7 +908,7 @@ async def get_terminal_cwd( timeout=aiohttp.ClientTimeout(total=5), trust_env=True, ) as session: - async with session.get(cwd_url, headers=headers, cookies=cookies or {}) as resp: + async with session.get(cwd_url, headers=headers, cookies=cookies or {}, ssl=AIOHTTP_CLIENT_SESSION_SSL) as resp: if resp.status == 200: data = await resp.json() return data.get('cwd') @@ -916,7 +935,7 @@ async def get_terminal_system_prompt( trust_env=True, ) as session: # 1. Check feature flag - async with session.get(f'{base}/api/config') as resp: + async with session.get(f'{base}/api/config', ssl=AIOHTTP_CLIENT_SESSION_SSL) as resp: if resp.status != 200: return None config = await resp.json() @@ -924,7 +943,7 @@ async def get_terminal_system_prompt( return None # 2. Fetch system prompt - async with session.get(f'{base}/system', headers=headers, cookies=cookies or {}) as resp: + async with session.get(f'{base}/system', headers=headers, cookies=cookies or {}, ssl=AIOHTTP_CLIENT_SESSION_SSL) as resp: if resp.status == 200: data = await resp.json() return data.get('prompt') diff --git a/backend/open_webui/utils/webhook.py b/backend/open_webui/utils/webhook.py index 11c94675d1..ee7f3ab3b2 100644 --- a/backend/open_webui/utils/webhook.py +++ b/backend/open_webui/utils/webhook.py @@ -3,7 +3,7 @@ import logging import aiohttp from open_webui.config import WEBUI_FAVICON_URL -from open_webui.env import AIOHTTP_CLIENT_TIMEOUT, VERSION +from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL, AIOHTTP_CLIENT_TIMEOUT, VERSION log = logging.getLogger(__name__) @@ -53,7 +53,7 @@ async def post_webhook(name: str, url: str, message: str, event_data: dict) -> b async with aiohttp.ClientSession( trust_env=True, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT) ) as session: - async with session.post(url, json=payload) as r: + async with session.post(url, json=payload, ssl=AIOHTTP_CLIENT_SESSION_SSL) as r: r_text = await r.text() r.raise_for_status() log.debug(f'r.text: {r_text}') diff --git a/src/lib/apis/calendar/index.ts b/src/lib/apis/calendar/index.ts new file mode 100644 index 0000000000..b3148e6c18 --- /dev/null +++ b/src/lib/apis/calendar/index.ts @@ -0,0 +1,458 @@ +import { WEBUI_API_BASE_URL } from '$lib/constants'; + +export type CalendarModel = { + id: string; + user_id: string; + name: string; + color: string | null; + is_default: boolean; + is_system: boolean; + data: Record | null; + meta: Record | null; + access_grants: any[]; + created_at: number; + updated_at: number; +}; + +export type CalendarEventAttendeeModel = { + id: string; + event_id: string; + user_id: string; + status: string; + meta: Record | null; + created_at: number; + updated_at: number; +}; + +export type CalendarEventModel = { + id: string; + calendar_id: string; + user_id: string; + title: string; + description: string | null; + start_at: number; + end_at: number | null; + all_day: boolean; + rrule: string | null; + color: string | null; + location: string | null; + data: Record | null; + meta: Record | null; + is_cancelled: boolean; + attendees: CalendarEventAttendeeModel[]; + created_at: number; + updated_at: number; + // Set by expand_recurring_event for recurring instances + instance_id?: string; +}; + +export type CalendarEventForm = { + calendar_id: string; + title: string; + description?: string; + start_at: number; + end_at?: number; + all_day?: boolean; + rrule?: string; + color?: string; + location?: string; + data?: Record; + meta?: Record; + attendees?: { user_id: string; status?: string }[]; +}; + +export type CalendarForm = { + name: string; + color?: string; + data?: Record; + meta?: Record; + access_grants?: { target_type: string; target_id: string; permission: string }[]; +}; + +// ── Calendars ───────────────────────────────── + +export const getCalendars = async (token: string): Promise => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/`, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + +export const createCalendar = async (token: string, form: CalendarForm): Promise => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/create`, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + }, + body: JSON.stringify(form) + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + +export const updateCalendar = async ( + token: string, + calendarId: string, + form: Partial +): Promise => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/${calendarId}/update`, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + }, + body: JSON.stringify(form) + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + +export const deleteCalendar = async (token: string, calendarId: string): Promise => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/${calendarId}/delete`, { + method: 'DELETE', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res?.status ?? false; +}; + +export const setDefaultCalendar = async ( + token: string, + calendarId: string +): Promise => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/${calendarId}/default`, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + +// ── Events ───────────────────────────────── + +export const getCalendarEvents = async ( + token: string, + start: string, + end: string, + calendarIds?: string[] +): Promise => { + let error = null; + + const params = new URLSearchParams(); + params.append('start', start); + params.append('end', end); + if (calendarIds && calendarIds.length > 0) { + params.append('calendar_ids', calendarIds.join(',')); + } + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/events?${params.toString()}`, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + +export const createCalendarEvent = async ( + token: string, + form: CalendarEventForm +): Promise => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/events/create`, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + }, + body: JSON.stringify(form) + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + +export const getCalendarEventById = async ( + token: string, + eventId: string +): Promise => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/events/${eventId}`, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + +export const updateCalendarEvent = async ( + token: string, + eventId: string, + form: Partial +): Promise => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/events/${eventId}/update`, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + }, + body: JSON.stringify(form) + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + +export const deleteCalendarEvent = async (token: string, eventId: string): Promise => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/events/${eventId}/delete`, { + method: 'DELETE', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res?.status ?? false; +}; + +export const rsvpCalendarEvent = async ( + token: string, + eventId: string, + status: string +): Promise<{ status: boolean; rsvp: string }> => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/events/${eventId}/rsvp`, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + }, + body: JSON.stringify({ status }) + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + +export const searchCalendarEvents = async ( + token: string, + query: string | null, + skip: number = 0, + limit: number = 30 +): Promise<{ items: CalendarEventModel[]; total: number }> => { + let error = null; + + const params = new URLSearchParams(); + if (query) params.append('query', query); + params.append('skip', skip.toString()); + params.append('limit', limit.toString()); + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/events/search?${params.toString()}`, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; diff --git a/src/lib/components/admin/Settings/General.svelte b/src/lib/components/admin/Settings/General.svelte index f2ba4a3ee1..ddb81e844b 100644 --- a/src/lib/components/admin/Settings/General.svelte +++ b/src/lib/components/admin/Settings/General.svelte @@ -740,6 +740,14 @@ {/if} +
+
+ {$i18n.t('Memories')} ({$i18n.t('Beta')}) +
+ + +
+
{$i18n.t('Notes')} ({$i18n.t('Beta')}) @@ -758,10 +766,18 @@
- {$i18n.t('Memories')} ({$i18n.t('Beta')}) + {$i18n.t('Calendar')}
- + +
+ +
+
+ {$i18n.t('Automations')} +
+ +
diff --git a/src/lib/components/admin/Users/Groups/Permissions.svelte b/src/lib/components/admin/Users/Groups/Permissions.svelte index 7bd8fd00e0..cbfcb67b0a 100644 --- a/src/lib/components/admin/Users/Groups/Permissions.svelte +++ b/src/lib/components/admin/Users/Groups/Permissions.svelte @@ -916,6 +916,22 @@
{/if}
+ +
+
+
+ {$i18n.t('Calendar')} +
+ +
+ {#if defaultPermissions?.features?.calendar && !permissions.features.calendar} +
+
+ {$i18n.t('This is a default user permission and will remain enabled.')} +
+
+ {/if} +

diff --git a/src/lib/components/calendar/CalendarEventChip.svelte b/src/lib/components/calendar/CalendarEventChip.svelte new file mode 100644 index 0000000000..b1c3552e6c --- /dev/null +++ b/src/lib/components/calendar/CalendarEventChip.svelte @@ -0,0 +1,32 @@ + + + + + diff --git a/src/lib/components/calendar/CalendarEventModal.svelte b/src/lib/components/calendar/CalendarEventModal.svelte new file mode 100644 index 0000000000..bba3b3426b --- /dev/null +++ b/src/lib/components/calendar/CalendarEventModal.svelte @@ -0,0 +1,295 @@ + + + +
+ +
+ + +
+ + +
+ +
+
{$i18n.t('Calendar')}
+ +
+ + +
+
{$i18n.t('When')}
+
+ + {#if !allDay} + + + + {/if} + +
+
+ + +
+
{$i18n.t('Location')}
+ +
+ + +
+
{$i18n.t('Reminder')}
+ +
+ + +
+
{$i18n.t('Description')}
+ +
+
+ + +
+
+ {#if event && !event.meta?.automation_id} + + {/if} +
+ +
+ + +
+
+
+
+ + diff --git a/src/lib/components/calendar/CalendarSidebar.svelte b/src/lib/components/calendar/CalendarSidebar.svelte new file mode 100644 index 0000000000..7ffec382ea --- /dev/null +++ b/src/lib/components/calendar/CalendarSidebar.svelte @@ -0,0 +1,233 @@ + + + + +
+ +
+
+
{miniMonthNames[miniMonth]} {miniYear}
+
+ + +
+
+ +
+ {#each ['S', 'M', 'T', 'W', 'T', 'F', 'S'] as d} +
{d}
+ {/each} +
+ +
+ {#each miniDays as day} + + {/each} +
+
+ + +
+
+
+ {$i18n.t('Calendars')} +
+
+ + {#each calendars as cal (cal.id)} +
+ + + {#if isDeletable(cal)} + + {/if} +
+ {/each} +
+
diff --git a/src/lib/components/calendar/CalendarView.svelte b/src/lib/components/calendar/CalendarView.svelte new file mode 100644 index 0000000000..c78de56d8f --- /dev/null +++ b/src/lib/components/calendar/CalendarView.svelte @@ -0,0 +1,323 @@ + + +
+ + {#if view === 'month'} +
+
+ {#each DAY_NAMES as day} +
+ {$i18n.t(day)} +
+ {/each} +
+ +
+ {#each monthDays as day, i} + {@const dayKey = new Date(day.getFullYear(), day.getMonth(), day.getDate()) + .getTime() + .toString()} + {@const dayEvents = eventsByDay[dayKey] || []} + {@const col = i % 7} + {@const row = Math.floor(i / 7)} + + {/each} +
+
+ + + {:else if view === 'week'} +
+
+
+
+
+
+ {#each weekDays as day} +
+
+ {DAY_NAMES[day.getDay()]} +
+
+ {day.getDate()} +
+
+ {/each} +
+ +
+ {#each hours as hour} +
+
+ {hour > 0 ? formatHour(hour) : ''} +
+ {#each weekDays as day} + {@const hourEvents = getEventsForHour(day, hour, filteredEvents)} + + {/each} +
+ {/each} +
+
+
+
+
+ + + {:else} +
+
+ {#each hours as hour} + {@const hourEvents = getEventsForHour(currentDate, hour, filteredEvents)} +
+
+ {formatHour(hour)} +
+ +
+ {/each} +
+
+ {/if} +
diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index c8f9694343..fbd91e512c 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -13,6 +13,7 @@ import { get, type Unsubscriber, type Writable } from 'svelte/store'; import type { i18n as i18nType } from 'i18next'; import { WEBUI_BASE_URL } from '$lib/constants'; + import equal from 'fast-deep-equal'; import { chatId, @@ -277,7 +278,7 @@ }; let oldSelectedModelIds = ['']; - $: if (JSON.stringify(selectedModelIds) !== JSON.stringify(oldSelectedModelIds)) { + $: if (!equal(selectedModelIds, oldSelectedModelIds)) { onSelectedModelIdsChange(); } @@ -512,7 +513,7 @@ } } history = history; - return; // Patches history.messages directly; skip the trailing write-back. + return; // Patches history.messages directly; skip the trailing write-back. } else if (type === 'chat:message:favorite') { // Update message favorite status message.favorite = data.favorite; @@ -674,7 +675,7 @@ if ( $selectedFolder && selectedModels.filter((modelId) => modelId !== '').length > 0 && - JSON.stringify($selectedFolder?.data?.model_ids) !== JSON.stringify(selectedModels) + !equal($selectedFolder?.data?.model_ids, selectedModels) ) { const res = await updateFolderById(localStorage.token, $selectedFolder.id, { data: { @@ -758,7 +759,7 @@ await tick(); if ( folder?.data?.model_ids && - JSON.stringify(selectedModels) !== JSON.stringify(folder.data.model_ids) + !equal(selectedModels, folder.data.model_ids) ) { selectedModels = folder.data.model_ids; @@ -1836,7 +1837,7 @@ chatFiles = chatFiles.filter( // Remove duplicates (item, index, array) => - array.findIndex((i) => JSON.stringify(i) === JSON.stringify(item)) === index + array.findIndex((i) => equal(i, item)) === index ); // Create user message @@ -1880,7 +1881,7 @@ $models.map((m) => m.id).includes(modelId) ? modelId : '' ); - if (JSON.stringify(selectedModels) !== JSON.stringify(_selectedModels)) { + if (!equal(selectedModels, _selectedModels)) { selectedModels = _selectedModels; } @@ -2177,7 +2178,7 @@ // Remove duplicates files = files.filter( (item, index, array) => - array.findIndex((i) => JSON.stringify(i) === JSON.stringify(item)) === index + array.findIndex((i) => equal(i, item)) === index ); scrollToBottom(); @@ -2412,8 +2413,11 @@ taskIds = newTaskIds; } - // Backend returns chat_id for new chats — set store + URL - if (res.chat_id && $chatId !== res.chat_id) { + // Backend returns chat_id for new chats — set store + URL. + // Only update if the user hasn't navigated to a different chat + // while the request was in flight (prevents overwriting $chatId + // and causing spurious toast notifications / state duplication). + if (res.chat_id && $chatId !== res.chat_id && $chatId === _chatId) { await chatId.set(res.chat_id); if (!$temporaryChatEnabled) { window.history.replaceState(history.state, '', `/c/${res.chat_id}`); diff --git a/src/lib/components/chat/Messages/Citations/CitationModal.svelte b/src/lib/components/chat/Messages/Citations/CitationModal.svelte index 9c17748cf1..0a5bb6c704 100644 --- a/src/lib/components/chat/Messages/Citations/CitationModal.svelte +++ b/src/lib/components/chat/Messages/Citations/CitationModal.svelte @@ -228,7 +228,9 @@ rawContent.length > CONTENT_PREVIEW_LIMIT && !expandedDocs.has(documentIdx)} {#if $settings?.renderMarkdownInPreviews ?? true} -
+
{ + speakAbort?.abort(); + speakAbort = null; + try { speechSynthesis.cancel(); $audioQueue?.stop(); } catch {} - if (speaking) { - speaking = false; - speakingIdx = undefined; - } + speaking = false; + speakingIdx = undefined; + loadingSpeech = false; }; + // Resolve voice: model-specific > user settings > config default + const getVoiceId = () => + model?.info?.meta?.tts?.voice ?? + ($settings?.audio?.tts?.defaultVoice === $config.audio.tts.voice + ? ($settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice) + : $config?.audio?.tts?.voice); + const speak = async () => { if (!(message?.content ?? '').trim().length) { toast.info($i18n.t('No content to speak')); return; } + stopAudio(); + speakAbort = new AbortController(); + const { signal } = speakAbort; + speaking = true; const content = removeAllDetails(message.content); - // Get voice: model-specific > user settings > config default - const getVoiceId = () => { - // Check for model-specific TTS voice first - if (model?.info?.meta?.tts?.voice) { - return model.info.meta.tts.voice; - } - // Fall back to user settings or config default - if ($settings?.audio?.tts?.defaultVoice === $config.audio.tts.voice) { - return $settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice; - } - return $config?.audio?.tts?.voice; - }; - if ($config.audio.tts.engine === '') { let voices = []; const getVoicesLoop = setInterval(() => { @@ -242,16 +243,10 @@ if (voices.length > 0) { clearInterval(getVoicesLoop); - const voiceId = getVoiceId(); - const voice = voices?.filter((v) => v.voiceURI === voiceId)?.at(0) ?? undefined; - - console.log(voice); - + const voice = voices.find((v) => v.voiceURI === getVoiceId()); const speech = new SpeechSynthesisUtterance(content); speech.rate = $settings.audio?.tts?.playbackRate ?? 1; - console.log(speech); - speech.onend = () => { speaking = false; if ($settings.conversationMode) { @@ -281,9 +276,7 @@ ); if (!messageContentParts.length) { - console.log('No content to speak'); toast.info($i18n.t('No content to speak')); - speaking = false; loadingSpeech = false; return; @@ -303,41 +296,43 @@ await $TTSWorker.init(); } - for (const [idx, sentence] of messageContentParts.entries()) { + for (const [, sentence] of messageContentParts.entries()) { + if (signal.aborted) return; + const url = await $TTSWorker - .generate({ - text: sentence, - voice: voiceId - }) + .generate({ text: sentence, voice: voiceId }) .catch((error) => { console.error(error); toast.error(`${error}`); - speaking = false; loadingSpeech = false; }); + if (signal.aborted) return; + if (url && speaking) { $audioQueue.enqueue(url); loadingSpeech = false; } } } else { - for (const [idx, sentence] of messageContentParts.entries()) { + for (const [, sentence] of messageContentParts.entries()) { + if (signal.aborted) return; + const res = await synthesizeOpenAISpeech(localStorage.token, voiceId, sentence).catch( (error) => { console.error(error); toast.error(`${error}`); - speaking = false; loadingSpeech = false; } ); + if (signal.aborted) return; + if (res && speaking) { const blob = await res.blob(); const url = URL.createObjectURL(blob); - $audioQueue.enqueue(url); loadingSpeech = false; } diff --git a/src/lib/components/chat/ModelSelector.svelte b/src/lib/components/chat/ModelSelector.svelte index 588352e725..bd609b344f 100644 --- a/src/lib/components/chat/ModelSelector.svelte +++ b/src/lib/components/chat/ModelSelector.svelte @@ -6,6 +6,7 @@ import Tooltip from '../common/Tooltip.svelte'; import { updateUserSettings } from '$lib/apis/users'; + import equal from 'fast-deep-equal'; const i18n = getContext('i18n'); export let selectedModels = ['']; @@ -43,7 +44,7 @@ $models.map((m) => m.id).includes(model) ? model : '' ); - if (JSON.stringify(_selectedModels) !== JSON.stringify(selectedModels)) { + if (!equal(_selectedModels, selectedModels)) { selectedModels = _selectedModels; } } diff --git a/src/lib/components/chat/Placeholder.svelte b/src/lib/components/chat/Placeholder.svelte index 76d1ecff02..8c998b357d 100644 --- a/src/lib/components/chat/Placeholder.svelte +++ b/src/lib/components/chat/Placeholder.svelte @@ -106,7 +106,7 @@ }} /> {:else} -
+
{#each models as model, modelIdx} diff --git a/src/lib/components/common/RichTextInput.svelte b/src/lib/components/common/RichTextInput.svelte index 673e651c79..8c4006d280 100644 --- a/src/lib/components/common/RichTextInput.svelte +++ b/src/lib/components/common/RichTextInput.svelte @@ -1,6 +1,7 @@ + { + if (e.key === 'Shift') shiftKey = true; + }} + on:keyup={(e) => { + if (e.key === 'Shift') shiftKey = false; + }} +/> + {$i18n.t('Settings')}
- {#if $user?.role === 'admin' || $user?.permissions?.features?.automations} - { - if (e.metaKey || e.ctrlKey || e.shiftKey || e.button === 1) return; - e.preventDefault(); - show = false; - goto('/automations'); - if ($mobile) { - await tick(); - showSidebar.set(false); - } - }} - > -
- - - -
-
{$i18n.t('Automations')}
-
- {/if} - {#if role === 'admin'} { @@ -261,7 +265,7 @@ } e.preventDefault(); show = false; - goto('/playground'); + goto('/admin'); if ($mobile) { await tick(); showSidebar.set(false); @@ -269,9 +273,9 @@ }} >
- +
-
{$i18n.t('Playground')}
+
{$i18n.t('Admin Panel')}
{/if} @@ -296,29 +300,261 @@
{$i18n.t('Archived Chats')}
+
+ + {#if $user?.role === 'admin' || $user?.permissions?.workspace?.models || $user?.permissions?.workspace?.knowledge || $user?.permissions?.workspace?.prompts || $user?.permissions?.workspace?.tools} + + {/if} + + {#if ($config?.features?.enable_notes ?? false) && ($user?.role === 'admin' || ($user?.permissions?.features?.notes ?? true))} + + {/if} + + {#if $config?.features?.enable_calendar && ($user?.role === 'admin' || $user?.permissions?.features?.calendar)} + + {/if} + + {#if $config?.features?.enable_automations && ($user?.role === 'admin' || $user?.permissions?.features?.automations)} + + {/if} + {#if role === 'admin'} - { - if (e.metaKey || e.ctrlKey || e.shiftKey || e.button === 1) { - return; - } - e.preventDefault(); - show = false; - goto('/admin'); - if ($mobile) { - await tick(); - showSidebar.set(false); - } - }} - > -
- -
-
{$i18n.t('Admin Panel')}
-
+ {/if} {#if help} diff --git a/src/lib/components/notes/NoteEditor.svelte b/src/lib/components/notes/NoteEditor.svelte index 8f387ed6ed..4216243857 100644 --- a/src/lib/components/notes/NoteEditor.svelte +++ b/src/lib/components/notes/NoteEditor.svelte @@ -8,6 +8,7 @@ import { marked } from 'marked'; import { toast } from 'svelte-sonner'; + import equal from 'fast-deep-equal'; import { goto } from '$app/navigation'; @@ -226,7 +227,7 @@ } function areContentsEqual(a, b) { - return JSON.stringify(a) === JSON.stringify(b); + return equal(a, b); } function insertNoteVersion(note) { diff --git a/src/lib/components/workspace/Models/BuiltinTools.svelte b/src/lib/components/workspace/Models/BuiltinTools.svelte index b900d004b3..fe99005688 100644 --- a/src/lib/components/workspace/Models/BuiltinTools.svelte +++ b/src/lib/components/workspace/Models/BuiltinTools.svelte @@ -50,6 +50,10 @@ automations: { label: $i18n.t('Automations'), description: $i18n.t('Create and manage scheduled automations') + }, + calendar: { + label: $i18n.t('Calendar'), + description: $i18n.t('List calendars, search, create, update, and delete calendar events') } }; diff --git a/src/lib/i18n/locales/ar-BH/translation.json b/src/lib/i18n/locales/ar-BH/translation.json index 0b22d8bc2c..1b4ff02105 100644 --- a/src/lib/i18n/locales/ar-BH/translation.json +++ b/src/lib/i18n/locales/ar-BH/translation.json @@ -77,9 +77,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "إضافة ملفات", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "إضافة ذكرايات", @@ -115,6 +117,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -277,6 +280,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", "Camera": "", @@ -527,6 +531,7 @@ "Delete automation?": "", "Delete Chat": "حذف المحادثه.", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -833,6 +838,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -1202,6 +1211,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "", "Live": "", "Llama.cpp": "", @@ -1212,6 +1222,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1321,6 +1332,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "المزيد", "More Concise": "", @@ -1339,6 +1351,7 @@ "New Automation": "", "New Button": "", "New Chat": "دردشة جديدة", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -2021,6 +2034,7 @@ "Title cannot be an empty string.": "العنوان مطلوب", "Title Generation": "", "Title Generation Prompt": "موجه إنشاء العنوان", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "للوصول إلى أسماء الموديلات المتاحة للتنزيل،", "To access the GGUF models available for downloading,": "للوصول إلى الموديلات GGUF المتاحة للتنزيل،", @@ -2191,6 +2205,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2198,6 +2213,7 @@ "What is shared:": "", "What's New in": "ما هو الجديد", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/ar/translation.json b/src/lib/i18n/locales/ar/translation.json index fc94ca4f79..49a3c5be10 100644 --- a/src/lib/i18n/locales/ar/translation.json +++ b/src/lib/i18n/locales/ar/translation.json @@ -77,9 +77,11 @@ "Add content here": "أضف المحتوى هنا", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "إضافة ملفات", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "إضافة ذاكرة", @@ -115,6 +117,7 @@ "AI": "", "All": "الكل", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "تم حذف جميع النماذج بنجاح", @@ -277,6 +280,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "التقويم", + "Calendars": "", "Call": "مكالمة", "Call feature is not supported when using Web STT engine": "ميزة الاتصال غير مدعومة عند استخدام محرك Web STT", "Camera": "الكاميرا", @@ -527,6 +531,7 @@ "Delete automation?": "", "Delete Chat": "حذف المحادثه.", "Delete chat?": "هل تريد حذف المحادثة؟", + "Delete Event": "", "Delete File": "", "Delete folder?": "هل تريد حذف المجلد؟", "Delete function?": "هل تريد حذف الوظيفة؟", @@ -833,6 +838,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "التقييمات", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "مفتاح API لـ Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "مثال: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "مثال: ALL", @@ -1202,6 +1211,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "جارٍ الاستماع...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1212,6 +1222,7 @@ "local": "", "Local": "محلي", "Local Task Model": "", + "Location": "", "Location access not allowed": "لا يُسمح بالوصول إلى الموقع", "Lost": "ضائع", "Low": "", @@ -1321,6 +1332,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "مفتاح API لـ Mojeek Search", + "Month": "", "Monthly": "", "More": "المزيد", "More Concise": "", @@ -1339,6 +1351,7 @@ "New Automation": "", "New Button": "", "New Chat": "دردشة جديدة", + "New Event": "", "New File": "", "New Folder": "مجلد جديد", "New Function": "", @@ -2021,6 +2034,7 @@ "Title cannot be an empty string.": "العنوان مطلوب", "Title Generation": "توليد العنوان", "Title Generation Prompt": "موجه إنشاء العنوان", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "للوصول إلى أسماء الموديلات المتاحة للتنزيل،", "To access the GGUF models available for downloading,": "للوصول إلى الموديلات GGUF المتاحة للتنزيل،", @@ -2191,6 +2205,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "ستقوم WebUI بإرسال الطلبات إلى \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "ستقوم WebUI بإرسال الطلبات إلى \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "ما الذي تحاول تحقيقه؟", "What are you working on?": "على ماذا تعمل؟", @@ -2198,6 +2213,7 @@ "What is shared:": "", "What's New in": "ما هو الجديد", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "عند التفعيل، سيستجيب النموذج لكل رسالة في المحادثة بشكل فوري، مولدًا الرد بمجرد إرسال المستخدم لرسالته. هذا الوضع مفيد لتطبيقات الدردشة الحية، لكنه قد يؤثر على الأداء في الأجهزة الأبطأ.", "wherever you are": "أينما كنت", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/az-AZ/translation.json b/src/lib/i18n/locales/az-AZ/translation.json index fe82205415..9e316d538d 100644 --- a/src/lib/i18n/locales/az-AZ/translation.json +++ b/src/lib/i18n/locales/az-AZ/translation.json @@ -73,9 +73,11 @@ "Add content here": "Məzmunu buraya əlavə edin", "Add Custom Parameter": "Fərdi parametr əlavə et", "Add Custom Prompt": "Fərdi prompt əlavə et", + "Add description": "", "Add Details": "Detallar əlavə et", "Add Files": "Fayl əlavə et", "Add Image": "Şəkil əlavə et", + "Add location": "", "Add Member": "Üzv əlavə et", "Add Members": "Üzvlər əlavə et", "Add Memory": "Yaddaş əlavə et", @@ -111,6 +113,7 @@ "AI": "Süni İntellekt (Sİ)", "All": "Hamısı", "All chats have been unarchived.": "Bütün çatlar arxivdən çıxarıldı.", + "All day": "", "All models are now hidden": "Bütün modellər indi gizlidir", "All models are now visible": "Bütün modellər indi görünür", "All models deleted successfully": "Bütün modellər uğurla silindi", @@ -273,6 +276,7 @@ "Bypass Web Loader": "Veb Yükləyicidən Yan Keç", "Cache Base Model List": "Əsas Model Siyahısını Keşlə", "Calendar": "Təqvim", + "Calendars": "", "Call": "Zəng", "Call feature is not supported when using Web STT engine": "Veb STT mühərriki istifadə edildikdə zəng funksiyası dəstəklənmir", "Camera": "Kamera", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "Çatı sil", "Delete chat?": "Çat silinsin?", + "Delete Event": "", "Delete File": "Faylı sil", "Delete folder?": "Qovluq silinsin?", "Delete function?": "Funksiya silinsin?", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Xəta: '{{modelId}}' ID-li model artıq mövcuddur. Davam etmək üçün fərqli bir ID seçin.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Xəta: Model ID-si boş ola bilməz. Davam etmək üçün etibarlı bir ID daxil edin.", "Evaluations": "Qiymətləndirmələr", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API Açarı", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Nümunə: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Nümunə: ALL (HAMISI)", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Eyni vaxtda aparılan axtarış sorğularını məhdudlaşdırın. 0 = limitsiz (standart). Ardıcıl icra üçün 1 təyin edin.", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Eyni vaxtda olan yerləşdirmə (embedding) sorğularının sayını məhdudlaşdırır. Limitsiz üçün 0 təyin edin.", "List": "Siyahı", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Dinlənilir...", "Live": "Canlı", "Llama.cpp": "Llama.cpp", @@ -1208,6 +1218,7 @@ "local": "yerli", "Local": "Yerli", "Local Task Model": "Yerli tapşırıq modeli", + "Location": "", "Location access not allowed": "Məkan girişinə icazə verilmir", "Lost": "İtirildi", "Low": "Aşağı", @@ -1317,6 +1328,7 @@ "Models Sharing": "Modellərin paylaşılması", "Mojeek": "Mojeek", "Mojeek Search API Key": "Mojeek Axtarış API Açarı", + "Month": "", "Monthly": "", "More": "Daha çox", "More Concise": "Daha yığcam", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "Yeni Düymə", "New Chat": "Yeni Çat", + "New Event": "", "New File": "Yeni Fayl", "New Folder": "Yeni Qovluq", "New Function": "Yeni Funksiya", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "Başlıq boş qala bilməz.", "Title Generation": "Başlıq yaradılması", "Title Generation Prompt": "Başlıq yaradılması üçün göstəriş", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Yükləmək üçün mövcud model adlarına daxil olmaq üçün,", "To access the GGUF models available for downloading,": "Yükləmək üçün mövcud GGUF modellərinə daxil olmaq üçün,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI \"{{url}}\" ünvanına sorğular göndərəcək", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI \"{{url}}/api/chat\" ünvanına sorğular göndərəcək", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI \"{{url}}/chat/completions\" ünvanına sorğular göndərəcək", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Nəyə nail olmaq istəyirsiniz?", "What are you working on?": "Nəyin üzərində işləyirsiniz?", @@ -2190,6 +2205,7 @@ "What is shared:": "Nələr paylaşılır:", "What's New in": "Yeniliklər:", "What's on your mind?": "Ağlınızda nə var?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Aktiv edildikdə, model hər bir mesajı real vaxt rejimində cavablandıracaq. Bu rejim canlı söhbət tətbiqləri üçün faydalıdır, lakin zəif avadanlıqlarda performansa təsir edə bilər.", "wherever you are": "harada olursunuzsa olun", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Nəticənin səhifələrə bölünüb-bölünməməsi. Hər səhifə üfüqi xətt və səhifə nömrəsi ilə ayrılacaq. İlkin olaraq False (Xeyr) seçilir.", diff --git a/src/lib/i18n/locales/bg-BG/translation.json b/src/lib/i18n/locales/bg-BG/translation.json index 646ae8592c..51dbe73be0 100644 --- a/src/lib/i18n/locales/bg-BG/translation.json +++ b/src/lib/i18n/locales/bg-BG/translation.json @@ -73,9 +73,11 @@ "Add content here": "Добавете съдържание тук", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Добавяне на Файлове", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Добавяне на Памет", @@ -111,6 +113,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Всички модели са изтрити успешно", @@ -273,6 +276,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "Календар", + "Calendars": "", "Call": "Обаждане", "Call feature is not supported when using Web STT engine": "Функцията за обаждане не се поддържа при използването на Web STT двигател", "Camera": "Камера", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "Изтриване на Чат", "Delete chat?": "Изтриване на чата?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Изтриване на папката?", "Delete function?": "Изтриване на функцията?", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Оценки", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "API ключ за Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Пример: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Пример: ВСИЧКИ", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Слушане...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1208,6 +1218,7 @@ "local": "", "Local": "Локално", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "Изгубено", "Low": "", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "API ключ за Mojeek Search", + "Month": "", "Monthly": "", "More": "Повече", "More Concise": "", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "", "New Chat": "Нов чат", + "New Event": "", "New File": "", "New Folder": "Нова папка", "New Function": "", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "Заглавието не може да бъде празно.", "Title Generation": "Генериране на заглавие", "Title Generation Prompt": "Промпт за генериране на заглавие", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "За достъп до наличните имена на моделите за изтегляне,", "To access the GGUF models available for downloading,": "За достъп до наличните GGUF модели за изтегляне,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI ще прави заявки към \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI ще прави заявки към \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Какво се опитвате да постигнете?", "What are you working on?": "Върху какво работите?", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "Какво е ново в", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Когато е активирано, моделът ще отговаря на всяко съобщение в чата в реално време, генерирайки отговор веднага щом потребителят изпрати съобщение. Този режим е полезен за приложения за чат на живо, но може да повлияе на производителността на по-бавен хардуер.", "wherever you are": "където и да сте", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/bn-BD/translation.json b/src/lib/i18n/locales/bn-BD/translation.json index 2a8c4c8a16..5a1589d3b4 100644 --- a/src/lib/i18n/locales/bn-BD/translation.json +++ b/src/lib/i18n/locales/bn-BD/translation.json @@ -73,9 +73,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "ফাইল যোগ করুন", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "মেমোরি যোগ করুন", @@ -111,6 +113,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -273,6 +276,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", "Camera": "", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "চ্যাট মুছে ফেলুন", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "", "Live": "", "Llama.cpp": "", @@ -1208,6 +1218,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "আরো", "More Concise": "", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "", "New Chat": "নতুন চ্যাট", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "শিরোনাম অবশ্যই একটি পাশাপাশি শব্দ হতে হবে।", "Title Generation": "", "Title Generation Prompt": "শিরোনামগঠন প্রম্পট", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "ডাউনলোডের জন্য এভেইলএবল মডেলের নামগুলো এক্সেস করতে,", "To access the GGUF models available for downloading,": "ডাউলোডের জন্য এভেইলএবল GGUF মডেলগুলো এক্সেস করতে,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "এতে নতুন কী", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/bo-TB/translation.json b/src/lib/i18n/locales/bo-TB/translation.json index 2d1dcc4d2e..c7f3716239 100644 --- a/src/lib/i18n/locales/bo-TB/translation.json +++ b/src/lib/i18n/locales/bo-TB/translation.json @@ -72,9 +72,11 @@ "Add content here": "ནང་དོན་འདིར་སྣོན་པ།", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "ཡིག་ཆ་སྣོན་པ།", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "དྲན་ཤེས་སྣོན་པ།", @@ -110,6 +112,7 @@ "AI": "", "All": "ཡོངས།", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "དཔེ་དབྱིབས་ཡོངས་རྫོགས་ལེགས་པར་བསུབས་ཟིན།", @@ -272,6 +275,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "ལོ་ཐོ།", + "Calendars": "", "Call": "སྐད་འབོད།", "Call feature is not supported when using Web STT engine": "Web STT མ་ལག་སྤྱོད་སྐབས་སྐད་འབོད་ཀྱི་ཁྱད་ཆོས་ལ་རྒྱབ་སྐྱོར་མེད།", "Camera": "པར་ཆས།", @@ -522,6 +526,7 @@ "Delete automation?": "", "Delete Chat": "ཁ་བརྡ་བསུབ་པ།", "Delete chat?": "ཁ་བརྡ་བསུབ་པ།?", + "Delete Event": "", "Delete File": "", "Delete folder?": "ཡིག་སྣོད་བསུབ་པ།?", "Delete function?": "ལས་འགན་བསུབ་པ།?", @@ -828,6 +833,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "གདེང་འཇོག", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API ལྡེ་མིག", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "དཔེར་ན། (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "དཔེར་ན། ALL", @@ -1197,6 +1206,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "ཉན་བཞིན་པ།...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1207,6 +1217,7 @@ "local": "", "Local": "ས་གནས།", "Local Task Model": "", + "Location": "", "Location access not allowed": "གནས་ཡུལ་འཛུལ་སྤྱོད་ལ་གནང་བ་མ་སྤྲད།", "Lost": "བརླགས།", "Low": "", @@ -1316,6 +1327,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API ལྡེ་མིག", + "Month": "", "Monthly": "", "More": "མང་བ།", "More Concise": "", @@ -1334,6 +1346,7 @@ "New Automation": "", "New Button": "", "New Chat": "ཁ་བརྡ་གསར་པ།", + "New Event": "", "New File": "", "New Folder": "ཡིག་སྣོད་གསར་པ།", "New Function": "", @@ -2011,6 +2024,7 @@ "Title cannot be an empty string.": "ཁ་བྱང་ཡིག་ཕྲེང་སྟོང་པ་ཡིན་མི་ཆོག", "Title Generation": "ཁ་བྱང་བཟོ་སྐྲུན།", "Title Generation Prompt": "ཁ་བྱང་བཟོ་སྐྲུན་གྱི་འགུལ་སློང་།", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "ཕབ་ལེན་གྱི་ཆེད་དུ་ཡོད་པའི་དཔེ་དབྱིབས་ཀྱི་མིང་ལ་འཛུལ་སྤྱོད་བྱེད་པར།:", "To access the GGUF models available for downloading,": "ཕབ་ལེན་གྱི་ཆེད་དུ་ཡོད་པའི་ GGUF དཔེ་དབྱིབས་ལ་འཛུལ་སྤྱོད་བྱེད་པར།:", @@ -2181,6 +2195,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI ཡིས་ \"{{url}}/api/chat\" ལ་རེ་ཞུ་གཏོང་ངེས།", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI ཡིས་ \"{{url}}/chat/completions\" ལ་རེ་ཞུ་གཏོང་ངེས།", + "Week": "", "Weekly": "", "What are you trying to achieve?": "ཁྱེད་ཀྱིས་ཅི་ཞིག་འགྲུབ་ཐབས་བྱེད་བཞིན་ཡོད།", "What are you working on?": "ཁྱེད་ཀྱིས་ཅི་ཞིག་ལས་ཀ་བྱེད་བཞིན་ཡོད།", @@ -2188,6 +2203,7 @@ "What is shared:": "", "What's New in": "གསར་པ་ཅི་ཡོད།", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "སྒུལ་བསྐྱོད་བྱས་ཚེ། དཔེ་དབྱིབས་ཀྱིས་ཁ་བརྡའི་འཕྲིན་རེ་རེར་དུས་ཐོག་ཏུ་ལན་འདེབས་བྱེད་ངེས། བེད་སྤྱོད་མཁན་གྱིས་འཕྲིན་བཏང་མ་ཐག་ལན་ཞིག་བཟོ་ངེས། མ་དཔེ་འདི་ཐད་གཏོང་ཁ་བརྡའི་བཀོལ་ཆས་ལ་ཕན་ཐོགས་ཡོད། འོན་ཀྱང་དེས་མཁྲེགས་ཆས་དལ་བའི་སྟེང་ལས་ཆོད་ལ་ཤུགས་རྐྱེན་ཐེབས་སྲིད།", "wherever you are": "ཁྱེད་གང་དུ་ཡོད་ཀྱང་།", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/bs-BA/translation.json b/src/lib/i18n/locales/bs-BA/translation.json index 72edaaa453..3316f8c4a7 100644 --- a/src/lib/i18n/locales/bs-BA/translation.json +++ b/src/lib/i18n/locales/bs-BA/translation.json @@ -74,9 +74,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Dodaj datoteke", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Dodaj memoriju", @@ -112,6 +114,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Svi modeli su uspjesno izbrisani", @@ -274,6 +277,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendars": "", "Call": "Poziv", "Call feature is not supported when using Web STT engine": "Značajka poziva nije podržana kada se koristi Web STT mehanizam", "Camera": "Kamera", @@ -524,6 +528,7 @@ "Delete automation?": "", "Delete Chat": "Izbriši razgovor", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -830,6 +835,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -1199,6 +1208,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Slušam...", "Live": "", "Llama.cpp": "", @@ -1209,6 +1219,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1318,6 +1329,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "Više", "More Concise": "", @@ -1336,6 +1348,7 @@ "New Automation": "", "New Button": "", "New Chat": "Novi razgovor", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -2015,6 +2028,7 @@ "Title cannot be an empty string.": "Naslov ne može biti prazni niz.", "Title Generation": "", "Title Generation Prompt": "Prompt za generiranje naslova", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "Za pristup dostupnim nazivima modela za preuzimanje,", "To access the GGUF models available for downloading,": "Za pristup GGUF modelima dostupnim za preuzimanje,", @@ -2185,6 +2199,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2192,6 +2207,7 @@ "What is shared:": "", "What's New in": "Što je novo u", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/ca-ES/translation.json b/src/lib/i18n/locales/ca-ES/translation.json index c041f14bd2..add558aebf 100644 --- a/src/lib/i18n/locales/ca-ES/translation.json +++ b/src/lib/i18n/locales/ca-ES/translation.json @@ -74,9 +74,11 @@ "Add content here": "Afegir contingut aquí", "Add Custom Parameter": "Afegir paràmetre personalitzat", "Add Custom Prompt": "Afegir indicació personalitzada", + "Add description": "", "Add Details": "Afegir detalls", "Add Files": "Afegir arxius", "Add Image": "Afegir imatge", + "Add location": "", "Add Member": "Afegir membre", "Add Members": "Afegir membres", "Add Memory": "Afegir memòria", @@ -112,6 +114,7 @@ "AI": "IA", "All": "Tots", "All chats have been unarchived.": "Tots els xats han estat desarxivats.", + "All day": "", "All models are now hidden": "Tots els models estan amagats, ara", "All models are now visible": "Tots els models són visibles, ara", "All models deleted successfully": "Tots els models s'han eliminat correctament", @@ -274,6 +277,7 @@ "Bypass Web Loader": "Ometre el càrregador web", "Cache Base Model List": "Llista de models base en memòria cau", "Calendar": "Calendari", + "Calendars": "", "Call": "Trucada", "Call feature is not supported when using Web STT engine": "La funció de trucada no s'admet quan s'utilitza el motor Web STT", "Camera": "Càmera", @@ -524,6 +528,7 @@ "Delete automation?": "Eliminar l'automatització", "Delete Chat": "Eliminar xat", "Delete chat?": "Eliminar el xat?", + "Delete Event": "", "Delete File": "Eliminar el fitxer", "Delete folder?": "Eliminar la carpeta?", "Delete function?": "Eliminar funció?", @@ -830,6 +835,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Error: Ja existeix un model amb l'ID '{{modelId}}'. Selecciona un ID diferent per continuar.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Error: ID de model no pot ser buit. Entra un ID de model vàlid per continuar.", "Evaluations": "Avaluacions", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Clau API d'EXA", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Exemple: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Exemple: TOTS", @@ -1199,6 +1208,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Limita les consultes de cerca simultànies. 0 = il·limitada (per defecte). Estableix-ho a 1 per a l'execució seqüencial (recomanat per a API amb límits de velocitat estrictes com el nivell gratuït de Brave).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Limita el nombre de sol·licituds d'incrustació simultànies. Estableix-ho a 0 per a un nombre il·limitat.", "List": "Llista", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Escoltant...", "Live": "Live", "Llama.cpp": "Llama.cpp", @@ -1209,6 +1219,7 @@ "local": "local", "Local": "Local", "Local Task Model": "Model local de tasques", + "Location": "", "Location access not allowed": "Accés a la ubicació no permesa", "Lost": "Perdut", "Low": "Baix", @@ -1318,6 +1329,7 @@ "Models Sharing": "Compartir els models", "Mojeek": "Mojeek", "Mojeek Search API Key": "Clau API de Mojeek Search", + "Month": "", "Monthly": "Cada mes", "More": "Més", "More Concise": "Més precís", @@ -1336,6 +1348,7 @@ "New Automation": "Nova automatització", "New Button": "Botó nou", "New Chat": "Nou xat", + "New Event": "", "New File": "Nou arxiu", "New Folder": "Nova carpeta", "New Function": "Nova funció", @@ -2015,6 +2028,7 @@ "Title cannot be an empty string.": "El títol no pot ser una cadena buida.", "Title Generation": "Generació de títols", "Title Generation Prompt": "Indicació de generació de títol", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Per accedir als noms dels models disponibles per descarregar,", "To access the GGUF models available for downloading,": "Per accedir als models GGUF disponibles per descarregar,", @@ -2185,6 +2199,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI farà peticions a \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI farà peticions a \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI farà peticions a \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "Cada setmana", "What are you trying to achieve?": "Què intentes aconseguir?", "What are you working on?": "En què estàs treballant?", @@ -2192,6 +2207,7 @@ "What is shared:": "Què es comparteix", "What's New in": "Què hi ha de nou a", "What's on your mind?": "Què tens en ment?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Quan està activat, el model respondrà a cada missatge de xat en temps real, generant una resposta tan bon punt l'usuari envia un missatge. Aquest mode és útil per a aplicacions de xat en directe, però pot afectar el rendiment en maquinari més lent.", "wherever you are": "allà on estiguis", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Si es pagina la sortida. Cada pàgina estarà separada per una regla horitzontal i un número de pàgina. Per defecte és Fals.", diff --git a/src/lib/i18n/locales/ceb-PH/translation.json b/src/lib/i18n/locales/ceb-PH/translation.json index ec4ea77ce4..db49608fee 100644 --- a/src/lib/i18n/locales/ceb-PH/translation.json +++ b/src/lib/i18n/locales/ceb-PH/translation.json @@ -73,9 +73,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Idugang ang mga file", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "", @@ -111,6 +113,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -273,6 +276,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", "Camera": "", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "", "Live": "", "Llama.cpp": "", @@ -1208,6 +1218,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "", "More Concise": "", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "", "New Chat": "Bag-ong diskusyon", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "", "Title Generation": "", "Title Generation Prompt": "Madasig nga henerasyon sa titulo", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "Aron ma-access ang mga ngalan sa modelo nga ma-download,", "To access the GGUF models available for downloading,": "Aron ma-access ang mga modelo sa GGUF nga magamit alang sa pag-download,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "Unsay bag-o sa", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/cs-CZ/translation.json b/src/lib/i18n/locales/cs-CZ/translation.json index 439154fb9c..b2ec0ebb05 100644 --- a/src/lib/i18n/locales/cs-CZ/translation.json +++ b/src/lib/i18n/locales/cs-CZ/translation.json @@ -75,9 +75,11 @@ "Add content here": "Zde přidejte obsah", "Add Custom Parameter": "Přidat vlastní parametr", "Add Custom Prompt": "", + "Add description": "", "Add Details": "Přidat podrobnosti", "Add Files": "Přidat soubory", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Přidat vzpomínku", @@ -113,6 +115,7 @@ "AI": "UI", "All": "Vše", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Všechny modely byly úspěšně smazány", @@ -275,6 +278,7 @@ "Bypass Web Loader": "Obejít webový zavaděč", "Cache Base Model List": "Ukládat seznam základních modelů do mezipaměti", "Calendar": "Kalendář", + "Calendars": "", "Call": "Volání", "Call feature is not supported when using Web STT engine": "Funkce volání není podporována při použití webového STT jádra.", "Camera": "Kamera", @@ -525,6 +529,7 @@ "Delete automation?": "", "Delete Chat": "Smazat konverzaci", "Delete chat?": "Smazat konverzaci?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Smazat složku?", "Delete function?": "Smazat funkci?", @@ -831,6 +836,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Chyba: Model s ID '{{modelId}}' již existuje. Pro pokračování prosím zvolte jiné ID.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Chyba: ID modelu nemůže být prázdné. Pro pokračování prosím zadejte platné ID.", "Evaluations": "Hodnocení", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "API klíč pro Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Příklad: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Příklad: VŠE", @@ -1200,6 +1209,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Poslouchám...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1210,6 +1220,7 @@ "local": "", "Local": "Lokální", "Local Task Model": "Lokální model pro úkoly", + "Location": "", "Location access not allowed": "Přístup k poloze nebyl povolen", "Lost": "Prohrál", "Low": "Nízká", @@ -1319,6 +1330,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "API klíč pro Mojeek Search", + "Month": "", "Monthly": "", "More": "Více", "More Concise": "Stručnější", @@ -1337,6 +1349,7 @@ "New Automation": "", "New Button": "Nové tlačítko", "New Chat": "Nová konverzace", + "New Event": "", "New File": "", "New Folder": "Nová složka", "New Function": "Nová funkce", @@ -2017,6 +2030,7 @@ "Title cannot be an empty string.": "Název nemůže být prázdný řetězec.", "Title Generation": "Generování názvu", "Title Generation Prompt": "Instrukce pro generování názvu", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Pro přístup k dostupným názvům modelů ke stažení,", "To access the GGUF models available for downloading,": "Pro přístup k modelům GGUF dostupným ke stažení,", @@ -2187,6 +2201,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI bude odesílat požadavky na \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI bude odesílat požadavky na \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI bude odesílat požadavky na \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Čeho se snažíte dosáhnout?", "What are you working on?": "Na čem pracujete?", @@ -2194,6 +2209,7 @@ "What is shared:": "", "What's New in": "Co je nového v", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Když je povoleno, model bude odpovídat na každou zprávu v konverzaci v reálném čase a generovat odpověď, jakmile uživatel odešle zprávu. Tento režim je užitečný pro aplikace s živou konverzací, ale může ovlivnit výkon na pomalejším hardwaru.", "wherever you are": "ať jste kdekoli", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Zda stránkovat výstup. Každá stránka bude oddělena vodorovnou čarou a číslem stránky. Výchozí hodnota je False.", diff --git a/src/lib/i18n/locales/da-DK/translation.json b/src/lib/i18n/locales/da-DK/translation.json index 3124250a0e..09d336d179 100644 --- a/src/lib/i18n/locales/da-DK/translation.json +++ b/src/lib/i18n/locales/da-DK/translation.json @@ -73,9 +73,11 @@ "Add content here": "Tilføj indhold her", "Add Custom Parameter": "Tilføj brugerdefineret parameter", "Add Custom Prompt": "Tilføj brugerdefineret prompt", + "Add description": "", "Add Details": "Tilføj detaljer", "Add Files": "Tilføj filer", "Add Image": "", + "Add location": "", "Add Member": "Tilføj medlem", "Add Members": "Tilføj medlemmer", "Add Memory": "Tilføj hukommelse", @@ -111,6 +113,7 @@ "AI": "AI", "All": "Alle", "All chats have been unarchived.": "Alle chatte er blevet aktive", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Alle modeller slettet uden fejl", @@ -273,6 +276,7 @@ "Bypass Web Loader": "Omgå Web Loader", "Cache Base Model List": "Cache Base Model List", "Calendar": "Kalender", + "Calendars": "", "Call": "Opkald", "Call feature is not supported when using Web STT engine": "Opkaldsfunktion er ikke understøttet for Web STT engine", "Camera": "Kamera", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "Slet chat", "Delete chat?": "Slet chat?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Slet mappe?", "Delete function?": "Slet funktion?", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Fejl: En model med ID '{{modelId}}' eksisterer allerede. Vælg venligst et andet ID for at fortsætte.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Fejl: Model ID kan ikke være tomt. Indtast venligst et gyldigt ID for at fortsætte.", "Evaluations": "Evalueringer", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API-nøgle", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Eksempel: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Eksempel: ALL", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Lytter...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1208,6 +1218,7 @@ "local": "lokal", "Local": "Lokal", "Local Task Model": "Lokal opgavemodel", + "Location": "", "Location access not allowed": "Adgang til placering ikke tilladt", "Lost": "Tabt", "Low": "Lav", @@ -1317,6 +1328,7 @@ "Models Sharing": "Modeldeling", "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API nøgle", + "Month": "", "Monthly": "", "More": "Mere", "More Concise": "Mere kortfattet", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "Ny knap", "New Chat": "Ny chat", + "New Event": "", "New File": "", "New Folder": "Ny mappe", "New Function": "Ny funktion", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "Titel kan ikke være en tom streng.", "Title Generation": "Titel-generation", "Title Generation Prompt": "Prompt til titelgenerering", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "For at få adgang til de tilgængelige modelnavne til download,", "To access the GGUF models available for downloading,": "For at få adgang til de GGUF-modeller, der er tilgængelige til download,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI vil lave forespørgsler til \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI vil lave forespørgsler til \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI vil lave forespørgsler til \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Hvad prøver du at opnå?", "What are you working on?": "Hvad arbejder du på?", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "Nyheder i", "What's on your mind?": "Hvad har du på hjertet?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Når aktiveret, vil modellen reagere på hver chatbesked i realtid og generere et svar, så snart brugeren sender en besked. Denne tilstand er nyttig til live chat-applikationer, men kan påvirke ydeevnen på langsommere hardware.", "wherever you are": "hvad end du er", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Om outputtet skal pagineres. Hver side vil være adskilt af en vandret streg og sidetal. Standard er False.", diff --git a/src/lib/i18n/locales/de-DE/translation.json b/src/lib/i18n/locales/de-DE/translation.json index 53a11c881d..5cd8fc30e6 100644 --- a/src/lib/i18n/locales/de-DE/translation.json +++ b/src/lib/i18n/locales/de-DE/translation.json @@ -73,9 +73,11 @@ "Add content here": "Inhalt hier hinzufügen", "Add Custom Parameter": "Benutzerdefinierten Parameter hinzufügen", "Add Custom Prompt": "Benutzerdefinierten Prompt hinzufügen", + "Add description": "", "Add Details": "Details hinzufügen", "Add Files": "Dateien hinzufügen", "Add Image": "Bild hinzufügen", + "Add location": "", "Add Member": "Mitglied hinzufügen", "Add Members": "Mitglieder hinzufügen", "Add Memory": "Erinnerung hinzufügen", @@ -111,6 +113,7 @@ "AI": "KI", "All": "Alle", "All chats have been unarchived.": "Alle Chats wurden aus dem Archiv wiederhergestellt.", + "All day": "", "All models are now hidden": "Alle Modelle sind nun versteckt", "All models are now visible": "Alle Modelle sind nun sichtbar", "All models deleted successfully": "Alle Modelle erfolgreich gelöscht", @@ -273,6 +276,7 @@ "Bypass Web Loader": "Web-Loader umgehen", "Cache Base Model List": "Basismodell-Liste cachen", "Calendar": "Kalender", + "Calendars": "", "Call": "Anruf", "Call feature is not supported when using Web STT engine": "Die Anruffunktion wird bei Verwendung der Web-STT-Engine nicht unterstützt.", "Camera": "Kamera", @@ -523,6 +527,7 @@ "Delete automation?": "Automatisierung löschen?", "Delete Chat": "Chat löschen", "Delete chat?": "Chat löschen?", + "Delete Event": "", "Delete File": "Datei löschen", "Delete folder?": "Ordner löschen?", "Delete function?": "Funktion löschen?", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Fehler: Ein Modell mit der ID '{{modelId}}' existiert bereits. Bitte wählen Sie eine andere ID.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Fehler: Die Modell-ID darf nicht leer sein. Bitte geben Sie eine gültige ID ein.", "Evaluations": "Evaluationen", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API-Schlüssel", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Bsp: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Bsp: ALL", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Gleichzeitige Suchanfragen begrenzen. 0 = unbegrenzt (Standard). Auf 1 setzen für sequentielle Ausführung (empfohlen für APIs mit strengen Ratenbegrenzungen wie dem kostenlosen Brave-Tarif).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Limitiert die Anzahl gleichzeitiger embedding Anfragen. Auf 0 setzen für unlimitiert.", "List": "Liste", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Höre zu...", "Live": "Live", "Llama.cpp": "Llama.cpp", @@ -1208,6 +1218,7 @@ "local": "lokal", "Local": "Lokal", "Local Task Model": "Lokales Aufgabenmodell", + "Location": "", "Location access not allowed": "Standortzugriff nicht erlaubt", "Lost": "Verloren", "Low": "Niedrig", @@ -1317,6 +1328,7 @@ "Models Sharing": "Modelle teilen", "Mojeek": "Mojeek", "Mojeek Search API Key": "Mojeek Search API-Schlüssel", + "Month": "", "Monthly": "Monatlich", "More": "Mehr", "More Concise": "Kürzer", @@ -1335,6 +1347,7 @@ "New Automation": "Neue Automatisierung", "New Button": "Neuer Button", "New Chat": "Neuer Chat", + "New Event": "", "New File": "Neue Datei", "New Folder": "Neuer Ordner", "New Function": "Neue Funktion", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "Titel darf nicht leer sein.", "Title Generation": "Titelgenerierung", "Title Generation Prompt": "Titelgenerierungs-Prompt", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Um die verfügbaren Modellnamen für den Download anzuzeigen,", "To access the GGUF models available for downloading,": "Um die verfügbaren GGUF-Modelle für den Download anzuzeigen,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI wird Anfragen an \"{{url}}\" senden", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI wird Anfragen an \"{{url}}/api/chat\" senden", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI wird Anfragen an \"{{url}}/chat/completions\" senden", + "Week": "", "Weekly": "Wöchentlich", "What are you trying to achieve?": "Was möchten Sie erreichen?", "What are you working on?": "Woran arbeiten Sie?", @@ -2190,6 +2205,7 @@ "What is shared:": "Was geteilt wird:", "What's New in": "Neuigkeiten in", "What's on your mind?": "Was beschäftigt Sie?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Wenn aktiviert, antwortet das Modell in Echtzeit auf jede Chat-Nachricht. Dieser Modus ist nützlich für Live-Chats, kann jedoch die Leistung auf langsamerer Hardware beeinträchtigen.", "wherever you are": "wo immer Sie sind", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Ob die Ausgabe paginiert werden soll. Jede Seite wird durch eine horizontale Linie und Seitennummer getrennt. Standard ist False.", diff --git a/src/lib/i18n/locales/dg-DG/translation.json b/src/lib/i18n/locales/dg-DG/translation.json index 2c1e74d8cf..f1e6fddc73 100644 --- a/src/lib/i18n/locales/dg-DG/translation.json +++ b/src/lib/i18n/locales/dg-DG/translation.json @@ -73,9 +73,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Add Files", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "", @@ -111,6 +113,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -273,6 +276,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", "Camera": "", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "", "Live": "", "Llama.cpp": "", @@ -1208,6 +1218,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "", "More Concise": "", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "", "New Chat": "New Bark", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "", "Title Generation": "", "Title Generation Prompt": "Title Generation Prompt very prompt", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "To access the available model names for downloading, much access", "To access the GGUF models available for downloading,": "To access the GGUF models available for downloading, much access", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "What's New in much new", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/el-GR/translation.json b/src/lib/i18n/locales/el-GR/translation.json index 2fa8e4b9bf..3d59704cdb 100644 --- a/src/lib/i18n/locales/el-GR/translation.json +++ b/src/lib/i18n/locales/el-GR/translation.json @@ -73,9 +73,11 @@ "Add content here": "Προσθέστε περιεχόμενο εδώ", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Προσθήκη Αρχείων", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Προσθήκη Μνήμης", @@ -111,6 +113,7 @@ "AI": "", "All": "Όλα", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Όλα τα μοντέλα διαγράφηκαν με επιτυχία", @@ -273,6 +276,7 @@ "Bypass Web Loader": "Παράκαμψη Φορτωτή Διαδικτύου", "Cache Base Model List": "Αποθήκευση Λίστας Βασικών Μοντέλων Στην Κρυφή Μνήμη", "Calendar": "", + "Calendars": "", "Call": "Κλήση", "Call feature is not supported when using Web STT engine": "Η λειτουργία κλήσης δεν υποστηρίζεται όταν χρησιμοποιείται η μηχανή Web STT", "Camera": "Κάμερα", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "Διαγραφή Συνομιλίας", "Delete chat?": "Διαγραφή συνομιλίας;", + "Delete Event": "", "Delete File": "", "Delete folder?": "Διαγραφή φακέλου;", "Delete function?": "Διαγραφή λειτουργίας;", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Αξιολογήσεις", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "API κλειδί του Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Παράδειγμα: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Παράδειγμα: ALL", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Ακούγεται...", "Live": "", "Llama.cpp": "", @@ -1208,6 +1218,7 @@ "local": "", "Local": "Τοπικά", "Local Task Model": "Τοπικό Μοντέλο Εργασιών", + "Location": "", "Location access not allowed": "Η πρόσβαση στην τοποθεσία δεν επιτρέπεται", "Lost": "Χαμένος", "Low": "", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Κλειδί API Mojeek Search", + "Month": "", "Monthly": "", "More": "Περισσότερα", "More Concise": "", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "", "New Chat": "Νέα Συνομιλία", + "New Event": "", "New File": "", "New Folder": "Νέος Φάκελος", "New Function": "Νέα Λειτουργία", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "Ο τίτλος δεν μπορεί να είναι κενή συμβολοσειρά.", "Title Generation": "Δημιουργία Τίτλου", "Title Generation Prompt": "Προτροπή Δημιουργίας Τίτλου", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "Για να αποκτήσετε πρόσβαση στα διαθέσιμα ονόματα μοντέλων για λήψη,", "To access the GGUF models available for downloading,": "Για να αποκτήσετε πρόσβαση στα μοντέλα GGUF διαθέσιμα για λήψη,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "Το WebUI θα κάνει αιτήματα στο \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "Το WebUI θα κάνει αιτήματα στο \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "Το WebUI θα κάνει αιτήματα στο \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Τι προσπαθείτε να πετύχετε?", "What are you working on?": "Τι εργάζεστε;", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "Τι νέο υπάρχει στο", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Όταν ενεργοποιηθεί, το μοντέλο θα ανταποκρίνεται σε κάθε μήνυμα συνομιλίας σε πραγματικό χρόνο, δημιουργώντας μια απάντηση μόλις ο χρήστης στείλει ένα μήνυμα. Αυτή η λειτουργία είναι χρήσιμη για εφαρμογές ζωντανής συνομιλίας, αλλά μπορεί να επηρεάσει την απόδοση σε πιο αργό υλικό.", "wherever you are": "οπουδήποτε βρίσκεστε", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/en-GB/translation.json b/src/lib/i18n/locales/en-GB/translation.json index 0cdc0ea0a7..d24b7aeda5 100644 --- a/src/lib/i18n/locales/en-GB/translation.json +++ b/src/lib/i18n/locales/en-GB/translation.json @@ -73,9 +73,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "", @@ -111,6 +113,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -273,6 +276,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", "Camera": "", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "", "Live": "", "Llama.cpp": "", @@ -1208,6 +1218,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "", "More Concise": "", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "", "New Chat": "", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "", "Title Generation": "", "Title Generation Prompt": "", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "", "To access the GGUF models available for downloading,": "", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/en-US/translation.json b/src/lib/i18n/locales/en-US/translation.json index 7850bd158d..b53f2ae485 100644 --- a/src/lib/i18n/locales/en-US/translation.json +++ b/src/lib/i18n/locales/en-US/translation.json @@ -73,9 +73,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "", @@ -111,6 +113,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -273,6 +276,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", "Camera": "", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "", "Live": "", "Llama.cpp": "", @@ -1208,6 +1218,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "", "More Concise": "", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "", "New Chat": "", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "", "Title Generation": "", "Title Generation Prompt": "", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "", "To access the GGUF models available for downloading,": "", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/es-ES/translation.json b/src/lib/i18n/locales/es-ES/translation.json index 183cf527e4..2958a4ddfd 100644 --- a/src/lib/i18n/locales/es-ES/translation.json +++ b/src/lib/i18n/locales/es-ES/translation.json @@ -74,9 +74,11 @@ "Add content here": "Añadir contenido aquí", "Add Custom Parameter": "Añadir Parámetro Personalizado", "Add Custom Prompt": "Añadir Indicador Personalizado", + "Add description": "", "Add Details": "Añadir Detalles", "Add Files": "Añadir Archivos", "Add Image": "Añadir Imagen", + "Add location": "", "Add Member": "Añadir Miembro", "Add Members": "Añadir Miembros", "Add Memory": "Añadir Memoria", @@ -112,6 +114,7 @@ "AI": "IA", "All": "Todos", "All chats have been unarchived.": "Todos los chats han sido desarchivados", + "All day": "", "All models are now hidden": "Todos los modelos están ahora ocultos", "All models are now visible": "Todos los modelos están ahora visibles", "All models deleted successfully": "Todos los modelos se han borrados correctamente", @@ -274,6 +277,7 @@ "Bypass Web Loader": "Desactivar Cargar de Web", "Cache Base Model List": "Cachear Lista de Cache Modelos", "Calendar": "Calendario", + "Calendars": "", "Call": "Llamada", "Call feature is not supported when using Web STT engine": "La funcionalidad de Llamada no está soportada cuando se usa el motor Web STT", "Camera": "Cámara", @@ -524,6 +528,7 @@ "Delete automation?": "¿Borrar automatización?", "Delete Chat": "Borrar Chat", "Delete chat?": "¿Borrar el chat?", + "Delete Event": "", "Delete File": "Borrar Fichero", "Delete folder?": "¿Borrar carpeta?", "Delete function?": "Borrar la función?", @@ -830,6 +835,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Error: Ya existe un modelo con el ID '{{modelId}}'. Seleccione otro ID para continuar.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Error: El ID del modelo no puede estar vacío. Ingrese un ID válido para continuar.", "Evaluations": "Evaluaciones", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Clave API de Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Ejemplo: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Ejemplo: TODOS", @@ -1199,6 +1208,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Limitar consultas de búsqueda simultáneas. 0 = ilimitado (predeterminado). Establécerlo en 1 para ejecución secuencial (recomendado para API con límites de velocidad estrictos, como la versión gratuita de Brave).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Limita el número de peticiones concurrentes al incrustrar. Ajusta a 0 para ilimitadas", "List": "Lista", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Escuchando...", "Live": "En Directo", "Llama.cpp": "Llama.cpp", @@ -1209,6 +1219,7 @@ "local": "local", "Local": "Local", "Local Task Model": "Modelo Local para Tarea", + "Location": "", "Location access not allowed": "Acceso a la Ubicación no permitido", "Lost": "Perdido", "Low": "Bajo", @@ -1318,6 +1329,7 @@ "Models Sharing": "Compartir Modelos", "Mojeek": "Mojeek", "Mojeek Search API Key": "Clave API de Mojeek Search", + "Month": "", "Monthly": "Mensual", "More": "Más", "More Concise": "Más Conciso", @@ -1336,6 +1348,7 @@ "New Automation": "Nueva Automatización", "New Button": "Nuevo Botón", "New Chat": "Nuevo Chat", + "New Event": "", "New File": "Nuevo Archivo", "New Folder": "Nueva Carpeta", "New Function": "Nueva Función", @@ -2015,6 +2028,7 @@ "Title cannot be an empty string.": "El título no puede ser una cadena vacía.", "Title Generation": "Generación de Títulos", "Title Generation Prompt": "Indicador para la Generación de Título", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Para acceder a los nombres de modelos disponibles para descargar,", "To access the GGUF models available for downloading,": "Para acceder a los modelos GGUF disponibles para descargar,", @@ -2185,6 +2199,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI hará solicitudes a \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI hará solicitudes a \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI hará solicitudes a \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "Semanal", "What are you trying to achieve?": "¿Qué estás tratando de conseguir?", "What are you working on?": "¿En qué estás trabajando?", @@ -2192,6 +2207,7 @@ "What is shared:": "Que es compartido:", "What's New in": "Que hay de Nuevo en", "What's on your mind?": "¿En que estás pensando?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Cuando está habilitado, el modelo responderá a cada mensaje de chat en tiempo real, generando una respuesta tan pronto como se envíe un mensaje. Este modo es útil para aplicaciones de chat en vivo, pero puede afectar al rendimiento en equipos más lentos.", "wherever you are": "dondequiera que estés", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Al paginar la salida. Cada página será separada por una línea horizontal y número de página. Por defecto: Falso", diff --git a/src/lib/i18n/locales/et-EE/translation.json b/src/lib/i18n/locales/et-EE/translation.json index d5624ef409..a7da9119d8 100644 --- a/src/lib/i18n/locales/et-EE/translation.json +++ b/src/lib/i18n/locales/et-EE/translation.json @@ -73,9 +73,11 @@ "Add content here": "Lisa siia sisu", "Add Custom Parameter": "Lisa kohandatud parameeter", "Add Custom Prompt": "Lisa kohandatud sisend", + "Add description": "", "Add Details": "Lisa üksikasjad", "Add Files": "Lisa faile", "Add Image": "Lisa pilt", + "Add location": "", "Add Member": "Lisa liige", "Add Members": "Lisa liikmeid", "Add Memory": "Lisa mälu", @@ -111,6 +113,7 @@ "AI": "AI", "All": "Kõik", "All chats have been unarchived.": "Kõik vestlused on arhiivist eemaldatud.", + "All day": "", "All models are now hidden": "Kõik mudelid on nüüd peidetud", "All models are now visible": "Kõik mudelid on nüüd nähtavad", "All models deleted successfully": "Kõik mudelid edukalt kustutatud", @@ -273,6 +276,7 @@ "Bypass Web Loader": "Jäta veebilaadija vahele", "Cache Base Model List": "Puhverda baasmudelite nimekiri", "Calendar": "Kalender", + "Calendars": "", "Call": "Kõne", "Call feature is not supported when using Web STT engine": "Kõnefunktsioon ei ole Web STT mootorit kasutades toetatud", "Camera": "Kaamera", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "Kustuta vestlus", "Delete chat?": "Kustutada vestlus?", + "Delete Event": "", "Delete File": "Kustuta fail", "Delete folder?": "Kustutada kaust?", "Delete function?": "Kustutada funktsioon?", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Viga: mudel ID-ga '{{modelId}}' on juba olemas. Palun valige jätkamiseks erinev ID.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Viga: mudeli ID ei saa olla tühi. Palun sisestage jätkamiseks kehtiv ID.", "Evaluations": "Hindamised", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API võti", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Näide: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Näide: ALL", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Piira samaaegseid otsingupäringuid. 0 = piiramatu (vaikimisi). Määrake 1 järjestikuse täitmise jaoks (soovitatav API-de puhul, millel on ranged piirangud, nagu Brave tasuta tase).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Piirab samaaegsete manustamispäringute arvu. Määrake 0 piirangu puudumiseks.", "List": "Nimekiri", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Kuulamine...", "Live": "Reaalajas", "Llama.cpp": "Llama.cpp", @@ -1208,6 +1218,7 @@ "local": "kohalik", "Local": "Kohalik", "Local Task Model": "Kohalik ülesande mudel", + "Location": "", "Location access not allowed": "Asukoha juurdepääs pole lubatud", "Lost": "Kaotanud", "Low": "Madal", @@ -1317,6 +1328,7 @@ "Models Sharing": "Mudelite jagamine", "Mojeek": "Mojeek", "Mojeek Search API Key": "Mojeek Search API võti", + "Month": "", "Monthly": "", "More": "Rohkem", "More Concise": "Kokkuvõtlikum", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "Uus nupp", "New Chat": "Uus vestlus", + "New Event": "", "New File": "Uus fail", "New Folder": "Uus kaust", "New Function": "Uus funktsioon", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "Pealkiri ei saa olla tühi string.", "Title Generation": "Pealkirja genereerimine", "Title Generation Prompt": "Pealkirja genereerimise sisend", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Juurdepääsuks saadaolevatele mudelinimedele allalaadimiseks,", "To access the GGUF models available for downloading,": "Juurdepääsuks allalaadimiseks saadaolevatele GGUF mudelitele,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI teeb päringuid aadressile \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI teeb päringuid aadressile \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI teeb päringuid aadressile \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Mida te püüate saavutada?", "What are you working on?": "Millega te tegelete?", @@ -2190,6 +2205,7 @@ "What is shared:": "Mida jagatakse:", "What's New in": "Mis on uut", "What's on your mind?": "Mis teil mõttes on?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Kui see on lubatud, vastab mudel igale vestlussõnumile reaalajas, genereerides vastuse niipea, kui kasutaja sõnumi saadab. See režiim on kasulik reaalajas vestlusrakendustes, kuid võib mõjutada jõudlust aeglasema riistvara puhul.", "wherever you are": "kus iganes te olete", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Kas lehekülgedele jagada. Iga leht eraldatakse horisontaalse joonega ja leheküljenumbriga. Vaikimisi välja lülitatud.", diff --git a/src/lib/i18n/locales/eu-ES/translation.json b/src/lib/i18n/locales/eu-ES/translation.json index ea86a7dee9..b8314d577a 100644 --- a/src/lib/i18n/locales/eu-ES/translation.json +++ b/src/lib/i18n/locales/eu-ES/translation.json @@ -73,9 +73,11 @@ "Add content here": "Gehitu edukia hemen", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Gehitu Fitxategiak", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Gehitu Memoria", @@ -111,6 +113,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Eredu guztiak ongi ezabatu dira", @@ -273,6 +276,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendars": "", "Call": "Deia", "Call feature is not supported when using Web STT engine": "Dei funtzioa ez da onartzen Web STT motorra erabiltzean", "Camera": "Kamera", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "Ezabatu Txata", "Delete chat?": "Ezabatu txata?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Ezabatu karpeta?", "Delete function?": "Ezabatu funtzioa?", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Ebaluazioak", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Adibidea: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Adibidea: GUZTIAK", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Entzuten...", "Live": "", "Llama.cpp": "", @@ -1208,6 +1218,7 @@ "local": "", "Local": "Lokala", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "Galduta", "Low": "", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Mojeek bilaketa API gakoa", + "Month": "", "Monthly": "", "More": "Gehiago", "More Concise": "", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "", "New Chat": "Txat berria", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "Izenburua ezin da kate hutsa izan.", "Title Generation": "", "Title Generation Prompt": "Izenburua sortzeko prompta", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Deskargatzeko eskuragarri dauden modelo izenak atzitzeko,", "To access the GGUF models available for downloading,": "Deskargatzeko eskuragarri dauden GGUF modeloak atzitzeko,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI-k eskaerak egingo ditu \"{{url}}/api/chat\"-era", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI-k eskaerak egingo ditu \"{{url}}/chat/completions\"-era", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Zer lortu nahi duzu?", "What are you working on?": "Zertan ari zara lanean?", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "Zer berri honetan:", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Gaituta dagoenean, modeloak txat mezu bakoitzari denbora errealean erantzungo dio, erantzun bat sortuz erabiltzaileak mezua bidaltzen duen bezain laster. Modu hau erabilgarria da zuzeneko txat aplikazioetarako, baina errendimenduan eragina izan dezake hardware motelagoan.", "wherever you are": "zauden tokian zaudela", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/fa-IR/translation.json b/src/lib/i18n/locales/fa-IR/translation.json index 38c1f63c14..3dd9dc4d32 100644 --- a/src/lib/i18n/locales/fa-IR/translation.json +++ b/src/lib/i18n/locales/fa-IR/translation.json @@ -73,9 +73,11 @@ "Add content here": "محتوا را اینجا اضافه کنید", "Add Custom Parameter": "افزودن پارامتر سفارشی", "Add Custom Prompt": "افزودن پرامپت سفارشی", + "Add description": "", "Add Details": "افزودن جزئیات", "Add Files": "افزودن فایل\u200cها", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "افزودن حافظه", @@ -111,6 +113,7 @@ "AI": "هوش مصنوعی", "All": "همه", "All chats have been unarchived.": "همه چت\u200cها از حالت بایگانی خارج شدند.", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "همه مدل\u200cها با موفقیت حذف شدند", @@ -273,6 +276,7 @@ "Bypass Web Loader": "دور زدن بارگذاری وب", "Cache Base Model List": "کش لیست مدل پایه", "Calendar": "تقویم", + "Calendars": "", "Call": "تماس", "Call feature is not supported when using Web STT engine": "ویژگی تماس هنگام استفاده از موتور Web STT پشتیبانی نمی\u200cشود", "Camera": "دوربین", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "حذف گپ", "Delete chat?": "گفتگو حذف شود؟", + "Delete Event": "", "Delete File": "", "Delete folder?": "پوشه حذف شود؟", "Delete function?": "تابع حذف شود؟", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "خطا: مدلی با شناسه '{{modelId}}' قبلاً وجود دارد. لطفاً برای ادامه، یک شناسه متفاوت انتخاب کنید.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "خطا: شناسه مدل نمی\u200cتواند خالی باشد. لطفاً برای ادامه، یک شناسه معتبر وارد کنید.", "Evaluations": "ارزیابی\u200cها", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "کلید API اکسا", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "مثال: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "مثال: ALL", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "در حال گوش دادن...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1208,6 +1218,7 @@ "local": "محلی", "Local": "محلی", "Local Task Model": "مدل وظیفه محلی", + "Location": "", "Location access not allowed": "دسترسی به موقعیت مکانی مجاز نیست", "Lost": "گم شده", "Low": "پایین", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "کلید API جستجوی موجیک", + "Month": "", "Monthly": "", "More": "بیشتر", "More Concise": "خلاصه\u200cتر", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "دکمه جدید", "New Chat": "گپ جدید", + "New Event": "", "New File": "", "New Folder": "پوشه جدید", "New Function": "تابع جدید", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "عنوان نمی تواند یک رشته خالی باشد.", "Title Generation": "تولید عنوان", "Title Generation Prompt": "پرامپت تولید عنوان", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "برای دسترسی به نام مدل های موجود برای دانلود،", "To access the GGUF models available for downloading,": "برای دسترسی به مدل\u200cهای GGUF موجود برای دانلود،", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI به \"{{url}}\" درخواست خواهد داد", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI به \"{{url}}/api/chat\" درخواست خواهد داد", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI به \"{{url}}/chat/completions\" درخواست خواهد داد", + "Week": "", "Weekly": "", "What are you trying to achieve?": "به دنبال دستیابی به چه هدفی هستید؟", "What are you working on?": "روی چه چیزی کار می\u200cکنید؟", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "چه چیز جدیدی در", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "وقتی فعال باشد، مدل به هر پیام گفتگو در زمان واقعی پاسخ می\u200cدهد و به محض ارسال پیام توسط کاربر، پاسخی تولید می\u200cکند. این حالت برای برنامه\u200cهای گفتگوی زنده مفید است، اما ممکن است در سخت\u200cافزارهای کندتر بر عملکرد تأثیر بگذارد.", "wherever you are": "هر جا که هستید", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "آیا خروجی صفحه\u200cبندی شود یا خیر. هر صفحه با یک خط افقی و شماره صفحه از هم جدا می\u200cشود. پیش\u200cفرض: False.", diff --git a/src/lib/i18n/locales/fi-FI/translation.json b/src/lib/i18n/locales/fi-FI/translation.json index fcdd7a48df..7c856082bc 100644 --- a/src/lib/i18n/locales/fi-FI/translation.json +++ b/src/lib/i18n/locales/fi-FI/translation.json @@ -73,9 +73,11 @@ "Add content here": "Lisää sisältöä tähän", "Add Custom Parameter": "Lisää mukautettu parametri", "Add Custom Prompt": "Lisää mukautettu kehote", + "Add description": "", "Add Details": "Lisää yksityiskohtia", "Add Files": "Lisää tiedostoja", "Add Image": "Lisää kuva", + "Add location": "", "Add Member": "Lisää jäsen", "Add Members": "Lisää jäseniä", "Add Memory": "Lisää muistiin", @@ -111,6 +113,7 @@ "AI": "AI", "All": "Kaikki", "All chats have been unarchived.": "Kaikki keskustelut poistettu arkistosta.", + "All day": "", "All models are now hidden": "Kaikki mallit ovat nyt piilotettu", "All models are now visible": "Kaikki mallit ovat nyt näkyvissä", "All models deleted successfully": "Kaikki mallit poistettu onnistuneesti", @@ -273,6 +276,7 @@ "Bypass Web Loader": "Ohita verkkolataaja", "Cache Base Model List": "Malli luettelon välimuisti", "Calendar": "Kalenteri", + "Calendars": "", "Call": "Puhelu", "Call feature is not supported when using Web STT engine": "Puhelutoimintoa ei tueta käytettäessä web-puheentunnistusmoottoria", "Camera": "Kamera", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "Poista keskustelu", "Delete chat?": "Haluatko varmasti poistaa tämän keskustelun?", + "Delete Event": "", "Delete File": "Poista tiedosto", "Delete folder?": "Haluatko varmasti poistaa tämän kansion?", "Delete function?": "Haluatko varmasti poistaa tämän toiminnon?", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Virhe: Malli '{{modelId}}' on jo käytössä. Valitse toinen ID jatkaaksesi.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Virhe: Mallin ID ei voi olla tyhjä. Kirjoita ID jatkaaksesi.", "Evaluations": "Arvioinnit", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API -avain", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Esimerkki: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Esimerkki: KAIKKI", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Rajoita samanaikaisia hakukyselyitä. 0 = rajoittamaton (oletus). Aseta arvoon 1 peräkkäistä suoritusta varten (suositellaan API-rajapinnoille, joilla on tiukat nopeusrajoitukset, kuten Brave-ilmaistaso).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Rajoittaa samanaikaisten upotuspyyntöjen määrää. Arvolla 0 ei rajoituksia.", "List": "Lista", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Kuuntelee...", "Live": "Live", "Llama.cpp": "Llama.cpp", @@ -1208,6 +1218,7 @@ "local": "paikallinen", "Local": "Paikallinen", "Local Task Model": "Paikallinen työmalli", + "Location": "", "Location access not allowed": "Ei pääsyä sijaintitietoihin", "Lost": "Mennyt", "Low": "Matala", @@ -1317,6 +1328,7 @@ "Models Sharing": "Mallien jako", "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API -avain", + "Month": "", "Monthly": "", "More": "Lisää", "More Concise": "Lyhyemmin", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "Uusi painike", "New Chat": "Uusi keskustelu", + "New Event": "", "New File": "Uusi tiedosto", "New Folder": "Uusi kansio", "New Function": "Uusi toiminto", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "Otsikko ei voi olla tyhjä merkkijono.", "Title Generation": "Otsikon luonti", "Title Generation Prompt": "Otsikon luontikehote", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Päästäksesi käsiksi ladattavissa oleviin mallinimiin,", "To access the GGUF models available for downloading,": "Päästäksesi käsiksi ladattavissa oleviin GGUF-malleihin,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI lähettää pyyntöjä osoitteeseen \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI lähettää pyyntöjä osoitteeseen \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI lähettää pyyntöjä osoitteeseen \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Mitä yrität saavuttaa?", "What are you working on?": "Mitä olet työskentelemässä?", @@ -2190,6 +2205,7 @@ "What is shared:": "Mitä jaetaan:", "What's New in": "Mitä uutta", "What's on your mind?": "Mitä ajattelet?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Kun käytössä, malli vastaa jokaiseen chatviestiin reaaliajassa, tuottaen vastauksen heti kun käyttäjä lähettää viestin. Tämä tila on hyödyllinen reaaliaikaisissa chat-sovelluksissa, mutta voi vaikuttaa suorituskykyyn hitaammilla laitteistoilla.", "wherever you are": "missä tahansa oletkin", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Sivutetaanko tuloste. Jokainen sivu erotetaan toisistaan vaakasuoralla viivalla ja sivunumerolla. Oletusarvo ei käytössä.", diff --git a/src/lib/i18n/locales/fr-CA/translation.json b/src/lib/i18n/locales/fr-CA/translation.json index 3be6cd20cd..a91ad0b618 100644 --- a/src/lib/i18n/locales/fr-CA/translation.json +++ b/src/lib/i18n/locales/fr-CA/translation.json @@ -74,9 +74,11 @@ "Add content here": "Ajoutez du contenu ici", "Add Custom Parameter": "Ajoutez votre réglage personnalisé", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Ajouter des fichiers", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Ajouter un souvenir", @@ -112,6 +114,7 @@ "AI": "", "All": "Tout", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Tous les modèles ont été supprimés avec succès", @@ -274,6 +277,7 @@ "Bypass Web Loader": "Ignorer le chargeur Web", "Cache Base Model List": "Mettre en cache la liste des modèles de base", "Calendar": "Calendrier", + "Calendars": "", "Call": "Appeler", "Call feature is not supported when using Web STT engine": "La fonction d'appel n'est pas prise en charge lors de l'utilisation du moteur Web STT", "Camera": "Appareil photo", @@ -524,6 +528,7 @@ "Delete automation?": "", "Delete Chat": "Supprimer la Conversation", "Delete chat?": "Supprimer la conversation ?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Supprimer le dossier ?", "Delete function?": "Supprimer la fonction ?", @@ -830,6 +835,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Évaluations", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Clé d'Exa API", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Exemple: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Exemple: TOUS", @@ -1199,6 +1208,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Écoute en cours...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1209,6 +1219,7 @@ "local": "", "Local": "Local", "Local Task Model": "Model de tâche local", + "Location": "", "Location access not allowed": "Accès à la localisation non autorisé", "Lost": "Perdu", "Low": "", @@ -1318,6 +1329,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Clé API Mojeek", + "Month": "", "Monthly": "", "More": "Plus", "More Concise": "", @@ -1336,6 +1348,7 @@ "New Automation": "", "New Button": "", "New Chat": "Nouvelle conversation", + "New Event": "", "New File": "", "New Folder": "Nouveau dossier", "New Function": "Nouvelle fonction", @@ -2015,6 +2028,7 @@ "Title cannot be an empty string.": "Le titre ne peut pas être une chaîne de caractères vide.", "Title Generation": "Génération du Titre", "Title Generation Prompt": "Prompt de génération de titre", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Pour accéder aux noms des modèles disponibles,", "To access the GGUF models available for downloading,": "Pour accéder aux modèles GGUF disponibles,", @@ -2185,6 +2199,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI effectuera des requêtes vers \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI fera des requêtes à \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI fera des requêtes à \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Que cherchez-vous à accomplir ?", "What are you working on?": "Sur quoi travaillez-vous ?", @@ -2192,6 +2207,7 @@ "What is shared:": "", "What's New in": "Quoi de neuf dans", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Lorsqu'il est activé, le modèle répondra à chaque message de la conversation en temps réel, générant une réponse dès que l'utilisateur envoie un message. Ce mode est utile pour les applications de conversation en direct, mais peut affecter les performances sur un matériel plus lent.", "wherever you are": "où que vous soyez", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Indique si la sortie doit être paginée. Chaque page sera séparée par une règle horizontale et un numéro de page. La valeur par défaut est False.", diff --git a/src/lib/i18n/locales/fr-FR/translation.json b/src/lib/i18n/locales/fr-FR/translation.json index 2d8625043b..0de23b8898 100644 --- a/src/lib/i18n/locales/fr-FR/translation.json +++ b/src/lib/i18n/locales/fr-FR/translation.json @@ -74,9 +74,11 @@ "Add content here": "Ajoutez du contenu ici", "Add Custom Parameter": "Ajoutez votre réglage personnalisé", "Add Custom Prompt": "Ajouter un prompt personnalisé", + "Add description": "", "Add Details": "Ajouter des détails", "Add Files": "Ajouter des fichiers", "Add Image": "Ajouter une image", + "Add location": "", "Add Member": "Ajouter un membre", "Add Members": "Ajouter des membres", "Add Memory": "Ajouter un souvenir", @@ -112,6 +114,7 @@ "AI": "IA", "All": "Tout", "All chats have been unarchived.": "Toutes les conversations ont été désarchivées.", + "All day": "", "All models are now hidden": "Tous les modèles sont maintenant masqués", "All models are now visible": "Tous les modèles sont maintenant visibles", "All models deleted successfully": "Tous les modèles supprimés avec succès", @@ -274,6 +277,7 @@ "Bypass Web Loader": "Ignorer le chargeur Web", "Cache Base Model List": "Mettre en cache la liste des modèles de base", "Calendar": "Calendrier", + "Calendars": "", "Call": "Appeler", "Call feature is not supported when using Web STT engine": "La fonction d'appel n'est pas prise en charge lors de l'utilisation du moteur Web STT", "Camera": "Appareil photo", @@ -524,6 +528,7 @@ "Delete automation?": "", "Delete Chat": "Supprimer la Conversation", "Delete chat?": "Supprimer la conversation ?", + "Delete Event": "", "Delete File": "Supprimer le fichier", "Delete folder?": "Supprimer le dossier ?", "Delete function?": "Supprimer la fonction ?", @@ -830,6 +835,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Erreur : Un modèle avec l'ID '{{modelId}}' existe déjà. Veuillez sélectionner un ID différent pour continuer.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Erreur : l'ID du modèle ne peut pas être vide. Veuillez saisir un ID valide pour continuer.", "Evaluations": "Évaluations", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Clé API Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Exemple: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Exemple: TOUS", @@ -1199,6 +1208,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Limite les requêtes de recherche simultanées. 0 = illimité (par défaut). Définir à 1 pour une exécution séquentielle (recommandé pour les API avec des limites de débit strictes comme Brave gratuit).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Limite le nombre de requêtes d'embedding simultanées. Définir à 0 pour illimité.", "List": "Liste", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Écoute en cours...", "Live": "Actif", "Llama.cpp": "Llama.cpp", @@ -1209,6 +1219,7 @@ "local": "local", "Local": "Local", "Local Task Model": "Model de tâche local", + "Location": "", "Location access not allowed": "Accès à la localisation non autorisé", "Lost": "Perdu", "Low": "Faible", @@ -1318,6 +1329,7 @@ "Models Sharing": "Partage des modèles", "Mojeek": "Mojeek", "Mojeek Search API Key": "Clé API Mojeek", + "Month": "", "Monthly": "", "More": "Plus", "More Concise": "Plus concis", @@ -1336,6 +1348,7 @@ "New Automation": "", "New Button": "Nouveau bouton", "New Chat": "Nouvelle conversation", + "New Event": "", "New File": "Nouveau fichier", "New Folder": "Nouveau dossier", "New Function": "Nouvelle fonction", @@ -2015,6 +2028,7 @@ "Title cannot be an empty string.": "Le titre ne peut pas être une chaîne de caractères vide.", "Title Generation": "Génération du Titre", "Title Generation Prompt": "Prompt de génération de titre", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Pour accéder aux noms des modèles disponibles,", "To access the GGUF models available for downloading,": "Pour accéder aux modèles GGUF disponibles,", @@ -2185,6 +2199,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI effectuera des requêtes vers \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI fera des requêtes à \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI fera des requêtes à \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Que cherchez-vous à accomplir ?", "What are you working on?": "Sur quoi travaillez-vous ?", @@ -2192,6 +2207,7 @@ "What is shared:": "Ce qui est partagé :", "What's New in": "Quoi de neuf dans", "What's on your mind?": "Quoi de neuf ?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Lorsqu'il est activé, le modèle répondra à chaque message de la conversation en temps réel, générant une réponse dès que l'utilisateur envoie un message. Ce mode est utile pour les applications de conversation en direct, mais peut affecter les performances sur un matériel plus lent.", "wherever you are": "où que vous soyez", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Indique si la sortie doit être paginée. Chaque page sera séparée par une règle horizontale et un numéro de page. La valeur par défaut est False.", diff --git a/src/lib/i18n/locales/gl-ES/translation.json b/src/lib/i18n/locales/gl-ES/translation.json index d014276c32..3c36e045e9 100644 --- a/src/lib/i18n/locales/gl-ES/translation.json +++ b/src/lib/i18n/locales/gl-ES/translation.json @@ -73,9 +73,11 @@ "Add content here": "Agrege contido aquí", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Agregar Arquivos", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Agregar Memoria", @@ -111,6 +113,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Todos os modelos han sido borrados", @@ -273,6 +276,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendars": "", "Call": "Chamada", "Call feature is not supported when using Web STT engine": "A funcionalidade da chamada non pode usarse xunto co motor da STT Web", "Camera": "Cámara", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "Borrar Chat", "Delete chat?": "Borrar o chat?", + "Delete Event": "", "Delete File": "", "Delete folder?": "¿Eliminar carpeta?", "Delete function?": "Borrar afunción?", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Evaluacions", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "chave API de Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Exemplo: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Exemplo: TODOS", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Escoitando...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1208,6 +1218,7 @@ "local": "", "Local": "Local", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "Perdido", "Low": "", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "chave API de Mojeek Search", + "Month": "", "Monthly": "", "More": "mais", "More Concise": "", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "", "New Chat": "Novo Chat", + "New Event": "", "New File": "", "New Folder": "Nova carpeta", "New Function": "", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "O título non pode ser unha cadena vacía.", "Title Generation": "Xeneración de titulos", "Title Generation Prompt": "Prompt de xeneración de título", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Para acceder os nomes de modelos dispoñibles para descargar,", "To access the GGUF models available for downloading,": "Para acceder os modelos GGUF dispoñibles para descargar,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI hará solicitudes a \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI hará solicitudes a \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "¿Qué estás tratando de lograr?", "What are you working on?": "¿En qué estás trabajando?", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "Novedades en", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Cando está habilitado, o modelo responderá a cada mensaxe de chat en tempo real, generando unha resposta tan pronto como o usuario envíe un mensaxe. Este modo es útil para aplicacions de chat en vivo, pero puede afectar o rendimiento en hardware mais lento.", "wherever you are": "Donde queira que estés", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/he-IL/translation.json b/src/lib/i18n/locales/he-IL/translation.json index b28ca3f237..2bb98c4d4e 100644 --- a/src/lib/i18n/locales/he-IL/translation.json +++ b/src/lib/i18n/locales/he-IL/translation.json @@ -74,9 +74,11 @@ "Add content here": "הוסף תוכן כאן", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "הוסף קבצים", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "הוסף זיכרון", @@ -112,6 +114,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "כל המודלים נמחקו בהצלחה", @@ -274,6 +277,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "לוח שנה", + "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", "Camera": "מצלמה", @@ -524,6 +528,7 @@ "Delete automation?": "", "Delete Chat": "מחק צ'אט", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -830,6 +835,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -1199,6 +1208,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "", "Live": "", "Llama.cpp": "", @@ -1209,6 +1219,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1318,6 +1329,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "עוד", "More Concise": "", @@ -1336,6 +1348,7 @@ "New Automation": "", "New Button": "", "New Chat": "צ'אט חדש", + "New Event": "", "New File": "", "New Folder": "תיקייה חדשה", "New Function": "פונקציה חדשה", @@ -2015,6 +2028,7 @@ "Title cannot be an empty string.": "שם לא יכול להיות מחרוזת ריקה.", "Title Generation": "", "Title Generation Prompt": "פרומפט ליצירת כותרת", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "כדי לגשת לשמות הדגמים הזמינים להורדה,", "To access the GGUF models available for downloading,": "כדי לגשת לדגמי GGUF הזמינים להורדה,", @@ -2185,6 +2199,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2192,6 +2207,7 @@ "What is shared:": "", "What's New in": "מה חדש ב", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/hi-IN/translation.json b/src/lib/i18n/locales/hi-IN/translation.json index 503262f4e4..ce96aa2286 100644 --- a/src/lib/i18n/locales/hi-IN/translation.json +++ b/src/lib/i18n/locales/hi-IN/translation.json @@ -73,9 +73,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "फाइलें जोड़ें", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "मेमोरी जोड़ें", @@ -111,6 +113,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -273,6 +276,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", "Camera": "", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "चैट हटाएं", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "", "Live": "", "Llama.cpp": "", @@ -1208,6 +1218,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "और..", "More Concise": "", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "", "New Chat": "नई चैट", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "शीर्षक नहीं खाली पाठ हो सकता है.", "Title Generation": "", "Title Generation Prompt": "शीर्षक जनरेशन प्रॉम्प्ट", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "डाउनलोड करने के लिए उपलब्ध मॉडल नामों तक पहुंचने के लिए,", "To access the GGUF models available for downloading,": "डाउनलोडिंग के लिए उपलब्ध GGUF मॉडल तक पहुँचने के लिए,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "इसमें नया क्या है", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/hr-HR/translation.json b/src/lib/i18n/locales/hr-HR/translation.json index feeffffaee..01e9f0fdf1 100644 --- a/src/lib/i18n/locales/hr-HR/translation.json +++ b/src/lib/i18n/locales/hr-HR/translation.json @@ -74,9 +74,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Dodaj datoteke", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Dodaj memoriju", @@ -112,6 +114,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -274,6 +277,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendars": "", "Call": "Poziv", "Call feature is not supported when using Web STT engine": "Značajka poziva nije podržana kada se koristi Web STT mehanizam", "Camera": "Kamera", @@ -524,6 +528,7 @@ "Delete automation?": "", "Delete Chat": "Izbriši razgovor", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -830,6 +835,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -1199,6 +1208,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Slušam...", "Live": "", "Llama.cpp": "", @@ -1209,6 +1219,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1318,6 +1329,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "Više", "More Concise": "", @@ -1336,6 +1348,7 @@ "New Automation": "", "New Button": "", "New Chat": "Novi razgovor", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -2015,6 +2028,7 @@ "Title cannot be an empty string.": "Naslov ne može biti prazni niz.", "Title Generation": "", "Title Generation Prompt": "Prompt za generiranje naslova", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "Za pristup dostupnim nazivima modela za preuzimanje,", "To access the GGUF models available for downloading,": "Za pristup GGUF modelima dostupnim za preuzimanje,", @@ -2185,6 +2199,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2192,6 +2207,7 @@ "What is shared:": "", "What's New in": "Što je novo u", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/hu-HU/translation.json b/src/lib/i18n/locales/hu-HU/translation.json index cd06ab36ab..5d2fee4e33 100644 --- a/src/lib/i18n/locales/hu-HU/translation.json +++ b/src/lib/i18n/locales/hu-HU/translation.json @@ -73,9 +73,11 @@ "Add content here": "Tartalom hozzáadása ide", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Fájlok hozzáadása", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Memória hozzáadása", @@ -111,6 +113,7 @@ "AI": "", "All": "Mind", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Minden modell sikeresen törölve", @@ -273,6 +276,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "Naptár", + "Calendars": "", "Call": "Hívás", "Call feature is not supported when using Web STT engine": "A hívás funkció nem támogatott Web STT motor használatakor", "Camera": "Kamera", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "Beszélgetés törlése", "Delete chat?": "Törli a beszélgetést?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Törli a mappát?", "Delete function?": "Törli a funkciót?", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Értékelések", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API kulcs", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Példa: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Példa: MIND", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Hallgatás...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1208,6 +1218,7 @@ "local": "", "Local": "Helyi", "Local Task Model": "", + "Location": "", "Location access not allowed": "Helyhozzáférés nem engedélyezett", "Lost": "Elveszett", "Low": "", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API kulcs", + "Month": "", "Monthly": "", "More": "Több", "More Concise": "", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "", "New Chat": "Új beszélgetés", + "New Event": "", "New File": "", "New Folder": "Új mappa", "New Function": "", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "A cím nem lehet üres karakterlánc.", "Title Generation": "Cím generálás", "Title Generation Prompt": "Cím generálási prompt", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "A letölthető modellek nevének eléréséhez,", "To access the GGUF models available for downloading,": "A letölthető GGUF modellek eléréséhez,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "A WebUI kéréseket küld a \"{{url}}\" címre", "WebUI will make requests to \"{{url}}/api/chat\"": "A WebUI kéréseket küld a \"{{url}}/api/chat\" címre", "WebUI will make requests to \"{{url}}/chat/completions\"": "A WebUI kéréseket küld a \"{{url}}/chat/completions\" címre", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Mit próbálsz elérni?", "What are you working on?": "Min dolgozol?", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "Mi újság a", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Ha engedélyezve van, a modell valós időben válaszol minden csevegőüzenetre, amint a felhasználó elküldi az üzenetet. Ez a mód hasznos élő csevegőalkalmazásokhoz, de lassabb hardveren befolyásolhatja a teljesítményt.", "wherever you are": "bárhol is vagy", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/id-ID/translation.json b/src/lib/i18n/locales/id-ID/translation.json index 364d35b33c..2e60de3ed1 100644 --- a/src/lib/i18n/locales/id-ID/translation.json +++ b/src/lib/i18n/locales/id-ID/translation.json @@ -72,9 +72,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Menambahkan File", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Menambahkan Memori", @@ -110,6 +112,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -272,6 +275,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendars": "", "Call": "Panggilan", "Call feature is not supported when using Web STT engine": "Fitur panggilan tidak didukung saat menggunakan mesin Web STT", "Camera": "Kamera", @@ -522,6 +526,7 @@ "Delete automation?": "", "Delete Chat": "Menghapus Obrolan", "Delete chat?": "Menghapus obrolan?", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "Fungsi hapus?", @@ -828,6 +833,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -1197,6 +1206,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Mendengarkan", "Live": "", "Llama.cpp": "", @@ -1207,6 +1217,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1316,6 +1327,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "Lainnya", "More Concise": "", @@ -1334,6 +1346,7 @@ "New Automation": "", "New Button": "", "New Chat": "Obrolan Baru", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -2011,6 +2024,7 @@ "Title cannot be an empty string.": "Judul tidak boleh berupa string kosong.", "Title Generation": "", "Title Generation Prompt": "Perintah Pembuatan Judul", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "Untuk mengakses nama model yang tersedia untuk diunduh,", "To access the GGUF models available for downloading,": "Untuk mengakses model GGUF yang tersedia untuk diunduh,", @@ -2181,6 +2195,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2188,6 +2203,7 @@ "What is shared:": "", "What's New in": "Apa yang Baru di", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/ie-GA/translation.json b/src/lib/i18n/locales/ie-GA/translation.json index 7603e2edcf..df9257c7e9 100644 --- a/src/lib/i18n/locales/ie-GA/translation.json +++ b/src/lib/i18n/locales/ie-GA/translation.json @@ -73,9 +73,11 @@ "Add content here": "Cuir ábhar anseo", "Add Custom Parameter": "Cuir Paraiméadar Saincheaptha leis", "Add Custom Prompt": "Cuir Treoir Shaincheaptha leis", + "Add description": "", "Add Details": "Cuir Sonraí leis", "Add Files": "Cuir Comhaid", "Add Image": "Cuir Íomhá leis", + "Add location": "", "Add Member": "Cuir Ball leis", "Add Members": "Cuir Baill leis", "Add Memory": "Cuir Cuimhne", @@ -111,6 +113,7 @@ "AI": "IS", "All": "Gach", "All chats have been unarchived.": "Tá na comhráite uile díchartlannaithe.", + "All day": "", "All models are now hidden": "Tá na samhlacha uile i bhfolach anois", "All models are now visible": "Tá na samhlacha uile le feiceáil anois", "All models deleted successfully": "Scriosadh na samhlacha go léir go rathúil", @@ -273,6 +276,7 @@ "Bypass Web Loader": "Seachbhóthar Luchtaire Gréasáin", "Cache Base Model List": "Liosta Samhail Bunáite Taisce", "Calendar": "Féilire", + "Calendars": "", "Call": "Glaoigh", "Call feature is not supported when using Web STT engine": "Ní thacaítear le gné glaonna agus inneall Web STT á úsáid", "Camera": "Ceamara", @@ -523,6 +527,7 @@ "Delete automation?": "Scrios an t-uathoibriú?", "Delete Chat": "Scrios Comhrá", "Delete chat?": "Scrios comhrá?", + "Delete Event": "", "Delete File": "Scrios Comhad", "Delete folder?": "Scrios fillteán?", "Delete function?": "Scrios feidhm?", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Earráid: Tá samhail leis an ID '{{modelId}}' ann cheana féin. Roghnaigh ID difriúil le dul ar aghaidh.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Earráid: Ní féidir ID an tSamhail a fhágáil folamh. Cuir isteach ID bailí le dul ar aghaidh.", "Evaluations": "Meastóireachtaí", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Eochair Exa API", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Sampla: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Sampla: GACH", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Teorainn a chur le fiosrúcháin chuardaigh chomhuaineacha. 0 = gan teorainn (réamhshocraithe). Socraigh go 1 le haghaidh forghníomhú seicheamhach (molta do APIanna le teorainneacha ráta dochta cosúil le sraith saor in aisce Brave).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Cuireann sé teorainn le líon na n-iarratas leabaithe comhuaineach. Socraigh go 0 le haghaidh neamhtheoranta.", "List": "Liosta", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Éisteacht...", "Live": "Beo", "Llama.cpp": "Llama.cpp", @@ -1208,6 +1218,7 @@ "local": "áitiúil", "Local": "Áitiúil", "Local Task Model": "Samhail Tasc Áitiúil", + "Location": "", "Location access not allowed": "Ní cheadaítear rochtain suímh", "Lost": "Cailleadh", "Low": "Íseal", @@ -1317,6 +1328,7 @@ "Models Sharing": "Roinnt Samhlacha", "Mojeek": "Mojeek", "Mojeek Search API Key": "Eochair API Cuardach Mojeek", + "Month": "", "Monthly": "Míosúil", "More": "Tuilleadh", "More Concise": "Níos Gonta", @@ -1335,6 +1347,7 @@ "New Automation": "Uathoibriú Nua", "New Button": "Cnaipe Nua", "New Chat": "Comhrá Nua", + "New Event": "", "New File": "Comhad Nua", "New Folder": "Fillteán Nua", "New Function": "Feidhm Nua", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "Ní féidir leis an teideal a bheith ina teaghrán folamh.", "Title Generation": "Giniúint Teidil", "Title Generation Prompt": "Treoir Giniúna Teidil", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Chun rochtain a fháil ar ainmneacha na samhlacha atá ar fáil lena n-íoslódáil,", "To access the GGUF models available for downloading,": "Chun rochtain a fháil ar na samhlacha GGUF atá ar fáil lena n-íoslódáil,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "Déanfaidh WebUI iarratais ar \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "Déanfaidh WebUI iarratais ar \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "Déanfaidh WebUI iarratais ar \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "Seachtainiúil", "What are you trying to achieve?": "Cad atá tú ag iarraidh a bhaint amach?", "What are you working on?": "Cad air a bhfuil tú ag obair?", @@ -2190,6 +2205,7 @@ "What is shared:": "Cad a roinntear:", "What's New in": "Cad atá Nua i", "What's on your mind?": "Cad atá ar d’intinn?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Nuair a bheidh sé cumasaithe, freagróidh an tsamhail gach teachtaireacht comhrá i bhfíor-am, ag giniúint freagra a luaithe a sheolann an t-úsáideoir teachtaireacht. Tá an mód seo úsáideach le haghaidh feidhmchláir chomhrá beo, ach d'fhéadfadh tionchar a bheith aige ar fheidhmíocht ar chrua-earraí níos moille.", "wherever you are": "aon áit a bhfuil tú", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Cibé acu an ndéanfar an t-aschur a roinnt le leathanaigh nó nach ndéanfar. Beidh riail chothrománach agus uimhir leathanaigh ag scartha ó gach leathanach. Is é Bréag an rogha réamhshocraithe.", diff --git a/src/lib/i18n/locales/it-IT/translation.json b/src/lib/i18n/locales/it-IT/translation.json index b284d6aa1d..e8b2b0f217 100644 --- a/src/lib/i18n/locales/it-IT/translation.json +++ b/src/lib/i18n/locales/it-IT/translation.json @@ -74,9 +74,11 @@ "Add content here": "Aggiungi un contenuto qui", "Add Custom Parameter": "Aggiungi Parametri Personalizzati", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Aggiungi dei file", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Aggiungi memoria", @@ -112,6 +114,7 @@ "AI": "", "All": "Tutti", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Tutti i modelli eliminati con successo", @@ -274,6 +277,7 @@ "Bypass Web Loader": "Bypassa il Web Loader", "Cache Base Model List": "", "Calendar": "Calendario", + "Calendars": "", "Call": "Chiamata", "Call feature is not supported when using Web STT engine": "La funzione di chiamata non è supportata quando si utilizza il motore Web STT", "Camera": "Fotocamera", @@ -524,6 +528,7 @@ "Delete automation?": "", "Delete Chat": "Elimina chat", "Delete chat?": "Elimina chat?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Elimina cartella?", "Delete function?": "Elimina funzione?", @@ -830,6 +835,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Valutazioni", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Chiave API Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Esempio: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Esempio: TUTTI", @@ -1199,6 +1208,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "In ascolto...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1209,6 +1219,7 @@ "local": "", "Local": "Locale", "Local Task Model": "Modello Task locale", + "Location": "", "Location access not allowed": "Accesso alla posizione non consentito", "Lost": "Perso", "Low": "", @@ -1318,6 +1329,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Chiave API di Mojeek Search", + "Month": "", "Monthly": "", "More": "Altro", "More Concise": "", @@ -1336,6 +1348,7 @@ "New Automation": "", "New Button": "", "New Chat": "Nuova chat", + "New Event": "", "New File": "", "New Folder": "Nuova cartella", "New Function": "", @@ -2015,6 +2028,7 @@ "Title cannot be an empty string.": "Il titolo non può essere una stringa vuota.", "Title Generation": "Generazione del titolo", "Title Generation Prompt": "Prompt di generazione del titolo", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Per accedere ai nomi dei modelli disponibili per il download,", "To access the GGUF models available for downloading,": "Per accedere ai modelli GGUF disponibili per il download,", @@ -2185,6 +2199,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI farà richieste a \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI farà richieste a \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI farà richieste a \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Cosa stai cercando di ottenere?", "What are you working on?": "Su cosa stai lavorando?", @@ -2192,6 +2207,7 @@ "What is shared:": "", "What's New in": "Novità in", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Quando abilitato, il modello risponderà a ciascun messaggio della chat in tempo reale, generando una risposta non appena l'utente invia un messaggio. Questa modalità è utile per le applicazioni di chat dal vivo, ma potrebbe influire sulle prestazioni su hardware più lento.", "wherever you are": "Ovunque tu sia", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Specifica se paginare l'output. Ogni pagina sarà separata da una riga orizzontale e dal numero di pagina. Predefinito è Falso.", diff --git a/src/lib/i18n/locales/ja-JP/translation.json b/src/lib/i18n/locales/ja-JP/translation.json index 95876c144c..77aa239d44 100644 --- a/src/lib/i18n/locales/ja-JP/translation.json +++ b/src/lib/i18n/locales/ja-JP/translation.json @@ -72,9 +72,11 @@ "Add content here": "ここへコンテンツを追加", "Add Custom Parameter": "カスタムパラメータを追加", "Add Custom Prompt": "カスタムプロンプトを追加", + "Add description": "", "Add Details": "より詳しく", "Add Files": "ファイルを追加", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "メモリを追加", @@ -110,6 +112,7 @@ "AI": "AI", "All": "全て", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "全てのモデルが正常に削除されました", @@ -272,6 +275,7 @@ "Bypass Web Loader": "Webローダーをバイパス", "Cache Base Model List": "ベースモデルリストをキャッシュ", "Calendar": "カレンダー", + "Calendars": "", "Call": "コール", "Call feature is not supported when using Web STT engine": "Web STTエンジンを使用している場合、コール機能は使用できません", "Camera": "カメラ", @@ -522,6 +526,7 @@ "Delete automation?": "オートメーションを削除しますか?", "Delete Chat": "チャットを削除", "Delete chat?": "チャットを削除しますか?", + "Delete Event": "", "Delete File": "", "Delete folder?": "フォルダーを削除しますか?", "Delete function?": "Functionを削除しますか?", @@ -828,6 +833,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "ID '{{modelId}}' のモデルはすでに存在します。他のIDを使用してください。", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "モデルIDを空にすることはできません。有効なIDを入力してください。", "Evaluations": "評価", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa APIキー", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "例: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "例: ALL", @@ -1197,6 +1206,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "リスト", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "聞いています...", "Live": "", "Llama.cpp": "", @@ -1207,6 +1217,7 @@ "local": "", "Local": "ローカル", "Local Task Model": "ローカルタスクモデル", + "Location": "", "Location access not allowed": "位置情報のアクセスが許可されていません", "Lost": "負け", "Low": "低", @@ -1316,6 +1327,7 @@ "Models Sharing": "モデルの共有", "Mojeek": "", "Mojeek Search API Key": "Mojeek Search APIキー", + "Month": "", "Monthly": "", "More": "もっと見る", "More Concise": "より簡潔に", @@ -1334,6 +1346,7 @@ "New Automation": "新しいオートメーション", "New Button": "新しいボタン", "New Chat": "新しいチャット", + "New Event": "", "New File": "", "New Folder": "新しいフォルダ", "New Function": "新しいFunction", @@ -2011,6 +2024,7 @@ "Title cannot be an empty string.": "タイトルは空文字列にできません。", "Title Generation": "タイトル生成", "Title Generation Prompt": "タイトル生成プロンプト", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "ダウンロード可能なモデル名にアクセスするには、", "To access the GGUF models available for downloading,": "ダウンロード可能な GGUF モデルにアクセスするには、", @@ -2181,6 +2195,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUIは\"{{url}}\"にリクエストを行います", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUIは\"{{url}}/api/chat\"にリクエストを行います", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUIは\"{{url}}/chat/completions\"にリクエストを行います", + "Week": "", "Weekly": "", "What are you trying to achieve?": "何を達成したいですか?", "What are you working on?": "何に取り組んでいますか?", @@ -2188,6 +2203,7 @@ "What is shared:": "", "What's New in": "新機能", "What's on your mind?": "今の状況を入力してください", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "有効にすると、ユーザのメッセージ送信と同時にリアルタイムで応答を生成します。ライブチャット用途に適しますが、性能の低い環境では動作が重くなる可能性があります。", "wherever you are": "どこにいても", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "出力をページ分けするかどうか。各ページは水平線とページ番号で分割されます。デフォルトでは無効", diff --git a/src/lib/i18n/locales/ka-GE/translation.json b/src/lib/i18n/locales/ka-GE/translation.json index f389a1f27c..b2726bf790 100644 --- a/src/lib/i18n/locales/ka-GE/translation.json +++ b/src/lib/i18n/locales/ka-GE/translation.json @@ -73,9 +73,11 @@ "Add content here": "შემცველობის აქ დამატება", "Add Custom Parameter": "მორგებული პარამეტრის დამატება", "Add Custom Prompt": "", + "Add description": "", "Add Details": "დეტალების დამატება", "Add Files": "ფაილების დამატება", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "მეხსიერების დამატება", @@ -111,6 +113,7 @@ "AI": "AI", "All": "ყველა", "All chats have been unarchived.": "ყველა ჩატი ამოღებული იქნა არქივიდან.", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "ყველა მოდელი წარმატებით წაიშალა", @@ -273,6 +276,7 @@ "Bypass Web Loader": "ვებჩამტვირთავის გამოტოვება", "Cache Base Model List": "საბაზისო მოდელების სიის დაკეშვა", "Calendar": "კალენდარი", + "Calendars": "", "Call": "ზარი", "Call feature is not supported when using Web STT engine": "", "Camera": "კამერა", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "საუბრის წაშლა", "Delete chat?": "წავშალო ჩატი?", + "Delete Event": "", "Delete File": "", "Delete folder?": "წავშალო საქაღალდეები?", "Delete function?": "წავშალო ფუნქცია?", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "შეფასებები", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API-ის გასაღები", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "მაგალითი: ALL", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "ვისმენ...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1208,6 +1218,7 @@ "local": "", "Local": "ლოკალური", "Local Task Model": "ლოკალური დავალების მოდელი", + "Location": "", "Location access not allowed": "მდებარეობასთან წვდომა დაშვებული არაა", "Lost": "წაგება", "Low": "დაბალი", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "მეტი", "More Concise": "", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "ახალი ღილაკი", "New Chat": "ახალი მიმოწერა", + "New Event": "", "New File": "", "New Folder": "ახალი საქაღალდე", "New Function": "ახალი ფუნქცია", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "სათაურის ველი ცარიელი სტრიქონი ვერ იქნება.", "Title Generation": "სათაურის გენერაცია", "Title Generation Prompt": "სათაურის შექმნის მოთხოვნა", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "ხელმისაწვდომი მოდელის სახელებთან წვდომისთვის, რომ გადმოწეროთ,", "To access the GGUF models available for downloading,": "გადმოსაწერად ხელმისაწვდომი GGUF მოდელებზე წვდომისთვის,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "რას ცდილობთ, მიაღწიოთ?", "What are you working on?": "რაზე მუშაობთ?", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "რა არის ახალი", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "სადაც არ უნდა ბრძანდებოდეთ", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/kab-DZ/translation.json b/src/lib/i18n/locales/kab-DZ/translation.json index 01da3096a4..4d0c32b8d6 100644 --- a/src/lib/i18n/locales/kab-DZ/translation.json +++ b/src/lib/i18n/locales/kab-DZ/translation.json @@ -73,9 +73,11 @@ "Add content here": "Rnu agbur da", "Add Custom Parameter": "Rnu aɣewwar udmawan", "Add Custom Prompt": "", + "Add description": "", "Add Details": "Rnu talqayt", "Add Files": "Rnu ifuyla", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Rnu cfawat", @@ -111,6 +113,7 @@ "AI": "TT", "All": "Akk", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Akk timudmiwin ttwakksent akken iwata", @@ -273,6 +276,7 @@ "Bypass Web Loader": "Zgel asalay Web", "Cache Base Model List": "Ffer tabdart n tmudmiwin n taffa", "Calendar": "Awitay", + "Calendars": "", "Call": "Siwel", "Call feature is not supported when using Web STT engine": "Tamahilt n usiwel ur tettwasefrak ara mi ara tesqedceḍ amsedday Web STT", "Camera": "Takamiṛatt", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "Kkes asqerdec", "Delete chat?": "Tebɣiḍ ad tekkseḍ adiwenni?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Kkes akaram?", "Delete function?": "Kkes tasɣent?", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Iktazalen", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Tasarut API n Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Amedya: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Amedya: AKK", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Yettmaḥsis…", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1208,6 +1218,7 @@ "local": "", "Local": "Adigan", "Local Task Model": "Tamudemt n temsekrit tadigant", + "Location": "", "Location access not allowed": "Anekcum ɣer tuddna", "Lost": "Iruḥ", "Low": "", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Tasarut API n Mojeek", + "Month": "", "Monthly": "", "More": "Ugar", "More Concise": "Awezlan ugar", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "Taqeffalt tamaynut", "New Chat": "Asqerdec amaynut", + "New Event": "", "New File": "", "New Folder": "Akaram amaynut", "New Function": "Tasɣent tamaynut", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "Azwel ur yettili ara d azrir ilem.", "Title Generation": "Asirew n uzwel", "Title Generation Prompt": "Aneftaɣ n usirew n uzwel", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Akken ad tkecmeḍ ɣer yismawen n tmudmiwin yellan i uzdam,", "To access the GGUF models available for downloading,": "Akken ad tkecmeḍ ɣer tmudmin GGUF yellan i usader,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI ad ssutreɣ \"{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI ad ssutreɣ i \"{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI ad ssutreɣ i \"{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Sanda ay tettarmed ad tessiwḍed?", "What are you working on?": "Ɣef wacu ay la tettmahaled?", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "D acu d amaynut deg", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "anda yebɣu tiliḍ", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Ma tebɣiḍ ad d-tessugneḍ tuffɣa. Yal asebter ad yebḍu s ulugen igli d wuṭṭun n usebter. Imezwura ɣer False.", diff --git a/src/lib/i18n/locales/ko-KR/translation.json b/src/lib/i18n/locales/ko-KR/translation.json index 7ca94f088d..2c4d22b843 100644 --- a/src/lib/i18n/locales/ko-KR/translation.json +++ b/src/lib/i18n/locales/ko-KR/translation.json @@ -72,9 +72,11 @@ "Add content here": "여기에 내용을 추가하세요", "Add Custom Parameter": "사용자 정의 매개변수 추가", "Add Custom Prompt": "사용자 정의 프롬프트 추가", + "Add description": "", "Add Details": "디테일 추가", "Add Files": "파일 추가", "Add Image": "", + "Add location": "", "Add Member": "멤버 추가", "Add Members": "멤버 추가", "Add Memory": "메모리 추가", @@ -110,6 +112,7 @@ "AI": "", "All": "전체", "All chats have been unarchived.": "모든 채팅이 보관 해제되었습니다.", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "성공적으로 모든 모델이 삭제되었습니다", @@ -272,6 +275,7 @@ "Bypass Web Loader": "웹 콘텐츠 불러오기 생략", "Cache Base Model List": "기본 모델 목록 캐시", "Calendar": "캘린더", + "Calendars": "", "Call": "음성 기능", "Call feature is not supported when using Web STT engine": "웹 STT 엔진 사용 시, 음성 기능은 지원되지 않습니다.", "Camera": "카메라", @@ -522,6 +526,7 @@ "Delete automation?": "", "Delete Chat": "채팅 삭제", "Delete chat?": "채팅을 삭제하시겠습니까?", + "Delete Event": "", "Delete File": "", "Delete folder?": "폴더를 삭제하시겠습니까?", "Delete function?": "함수를 삭제하시겠습니까?", @@ -828,6 +833,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "평가", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API 키", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "예: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "예: 전체", @@ -1197,6 +1206,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "듣는 중...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1207,6 +1217,7 @@ "local": "", "Local": "로컬", "Local Task Model": "로컬 작업 모델", + "Location": "", "Location access not allowed": "위치 접근이 허용되지 않습니다", "Lost": "패배", "Low": "", @@ -1316,6 +1327,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API 키", + "Month": "", "Monthly": "", "More": "더보기", "More Concise": "더 간결하게", @@ -1334,6 +1346,7 @@ "New Automation": "", "New Button": "새 버튼", "New Chat": "새 채팅", + "New Event": "", "New File": "", "New Folder": "새 폴더", "New Function": "새 함수", @@ -2011,6 +2024,7 @@ "Title cannot be an empty string.": "제목은 빈 문자열일 수 없습니다.", "Title Generation": "제목 생성", "Title Generation Prompt": "제목 생성 프롬프트", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "다운로드 가능한 모델명을 확인하려면,", "To access the GGUF models available for downloading,": "다운로드 가능한 GGUF 모델을 확인하려면,", @@ -2181,6 +2195,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI가 \"{{url}}\"로 요청을 보냅니다", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI가 \"{{url}}/api/chat\"로 요청을 보냅니다", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI가 \"{{url}}/chat/completions\"로 요청을 보냅니다", + "Week": "", "Weekly": "", "What are you trying to achieve?": "무엇을 성취하고 싶으신가요?", "What are you working on?": "어떤 작업을 하고 계신가요?", @@ -2188,6 +2203,7 @@ "What is shared:": "", "What's New in": "새로운 기능:", "What's on your mind?": "무슨 생각을 하고 계신가요?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "활성화하면 모델이 각 채팅 메시지에 실시간으로 응답하여 사용자가 메시지를 보내는 즉시 응답을 생성합니다. 이 모드는 실시간 채팅 애플리케이션에 유용하지만, 느린 하드웨어에서는 성능에 영향을 미칠 수 있습니다.", "wherever you are": "당신이 어디에 있든", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "출력을 페이지로 나눌지 여부입니다. 각 페이지는 구분선과 페이지 번호로 구분됩니다. 기본값은 False입니다.", diff --git a/src/lib/i18n/locales/lt-LT/translation.json b/src/lib/i18n/locales/lt-LT/translation.json index ce0cfb3401..0f2df1e48d 100644 --- a/src/lib/i18n/locales/lt-LT/translation.json +++ b/src/lib/i18n/locales/lt-LT/translation.json @@ -75,9 +75,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Pridėti failus", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Pridėti atminį", @@ -113,6 +115,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -275,6 +278,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendars": "", "Call": "Skambinti", "Call feature is not supported when using Web STT engine": "Skambučio funkcionalumas neleidžiamas naudojant Web STT variklį", "Camera": "Kamera", @@ -525,6 +529,7 @@ "Delete automation?": "", "Delete Chat": "Ištrinti pokalbį", "Delete chat?": "Ištrinti pokalbį?", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "Ištrinti funkciją", @@ -831,6 +836,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -1200,6 +1209,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Klausoma...", "Live": "", "Llama.cpp": "", @@ -1210,6 +1220,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1319,6 +1330,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "Daugiau", "More Concise": "", @@ -1337,6 +1349,7 @@ "New Automation": "", "New Button": "", "New Chat": "Naujas pokalbis", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -2017,6 +2030,7 @@ "Title cannot be an empty string.": "Pavadinimas negali būti tuščias", "Title Generation": "", "Title Generation Prompt": "Pavadinimo generavimo užklausa", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "Tam, kad prieiti prie galimų parsisiųsti modelių", "To access the GGUF models available for downloading,": "Tam, kad prieiti prie galimų parsisiųsti GGUF,", @@ -2187,6 +2201,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2194,6 +2209,7 @@ "What is shared:": "", "What's New in": "Kas naujo", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/lv-LV/translation.json b/src/lib/i18n/locales/lv-LV/translation.json index b3af1ec6a0..9b28e934cf 100644 --- a/src/lib/i18n/locales/lv-LV/translation.json +++ b/src/lib/i18n/locales/lv-LV/translation.json @@ -74,9 +74,11 @@ "Add content here": "Pievienojiet saturu šeit", "Add Custom Parameter": "Pievienot pielāgotu parametru", "Add Custom Prompt": "Pievienot pielāgotu uzvedni", + "Add description": "", "Add Details": "Pievienot detaļas", "Add Files": "Pievienot failus", "Add Image": "", + "Add location": "", "Add Member": "Pievienot dalībnieku", "Add Members": "Pievienot dalībniekus", "Add Memory": "Pievienot atmiņu", @@ -112,6 +114,7 @@ "AI": "MI", "All": "Visi", "All chats have been unarchived.": "Visas tērzēšanas ir atarhivētas.", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Visi modeļi veiksmīgi dzēsti", @@ -274,6 +277,7 @@ "Bypass Web Loader": "Apiet tīmekļa ielādētāju", "Cache Base Model List": "Kešot bāzes modeļu sarakstu", "Calendar": "Kalendārs", + "Calendars": "", "Call": "Zvans", "Call feature is not supported when using Web STT engine": "Zvana funkcija nav atbalstīta, izmantojot Web STT dzinēju", "Camera": "Kamera", @@ -524,6 +528,7 @@ "Delete automation?": "", "Delete Chat": "Dzēst tērzēšanu", "Delete chat?": "Dzēst tērzēšanu?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Dzēst mapi?", "Delete function?": "Dzēst funkciju?", @@ -830,6 +835,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Kļūda: Modelis ar ID '{{modelId}}' jau eksistē. Lūdzu, izvēlieties citu ID, lai turpinātu.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Kļūda: Modeļa ID nevar būt tukšs. Lūdzu, ievadiet derīgu ID, lai turpinātu.", "Evaluations": "Novērtējumi", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API atslēga", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Piemērs: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Piemērs: ALL", @@ -1199,6 +1208,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Ierobežot vienlaicīgos meklēšanas vaicājumus. 0 = neierobežots (noklusējums). Iestatiet 1 secīgai izpildei (ieteicams API ar stingriem ātruma ierobežojumiem, piemēram, Brave bezmaksas līmenim).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "Saraksts", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Klausās...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1209,6 +1219,7 @@ "local": "lokāls", "Local": "Lokāls", "Local Task Model": "Lokālais uzdevumu modelis", + "Location": "", "Location access not allowed": "Atrašanās vietas piekļuve nav atļauta", "Lost": "Zaudēts", "Low": "Zems", @@ -1318,6 +1329,7 @@ "Models Sharing": "Modeļu kopīgošana", "Mojeek": "Mojeek", "Mojeek Search API Key": "Mojeek Search API atslēga", + "Month": "", "Monthly": "", "More": "Vairāk", "More Concise": "Kodolīgāk", @@ -1336,6 +1348,7 @@ "New Automation": "", "New Button": "Jauna poga", "New Chat": "Jauna tērzēšana", + "New Event": "", "New File": "", "New Folder": "Jauna mape", "New Function": "Jauna funkcija", @@ -2015,6 +2028,7 @@ "Title cannot be an empty string.": "Virsraksts nevar būt tukša virkne.", "Title Generation": "Virsraksta ģenerēšana", "Title Generation Prompt": "Virsraksta ģenerēšanas uzvedne", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Lai piekļūtu pieejamajiem modeļu nosaukumiem lejupielādei,", "To access the GGUF models available for downloading,": "Lai piekļūtu GGUF modeļiem, kas pieejami lejupielādei,", @@ -2185,6 +2199,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI veiks pieprasījumus uz \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI veiks pieprasījumus uz \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI veiks pieprasījumus uz \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Ko jūs mēģināt sasniegt?", "What are you working on?": "Pie kā jūs strādājat?", @@ -2192,6 +2207,7 @@ "What is shared:": "Kas tiek kopīgots:", "What's New in": "Kas jauns", "What's on your mind?": "Par ko jūs domājat?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Ja iespējots, modelis atbildēs uz katru tērzēšanas ziņojumu reāllaikā, ģenerējot atbildi, tiklīdz lietotājs nosūta ziņojumu. Šis režīms ir noderīgs tiešsaistes tērzēšanas lietojumprogrammām, bet var ietekmēt veiktspēju lēnākā aparatūrā.", "wherever you are": "lai kur jūs būtu", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Vai lappušot izvadi. Katra lapa tiks atdalīta ar horizontālu līniju un lapas numuru. Noklusējums ir False.", diff --git a/src/lib/i18n/locales/ms-MY/translation.json b/src/lib/i18n/locales/ms-MY/translation.json index 81cf12b8f3..7f23e7ed77 100644 --- a/src/lib/i18n/locales/ms-MY/translation.json +++ b/src/lib/i18n/locales/ms-MY/translation.json @@ -72,9 +72,11 @@ "Add content here": "Tambah kandungan di sini", "Add Custom Parameter": "Tambah Parameter Tersuai", "Add Custom Prompt": "Tambah Prompt Tersuai", + "Add description": "", "Add Details": "Tambah Butiran", "Add Files": "Tambah Fail", "Add Image": "Tambah Imej", + "Add location": "", "Add Member": "Tambah Ahli", "Add Members": "Tambah Ahli", "Add Memory": "Tambah Memori", @@ -110,6 +112,7 @@ "AI": "AI", "All": "Semua", "All chats have been unarchived.": "Semua sembang telah nyaharkib.", + "All day": "", "All models are now hidden": "Semua model kini tersembunyi", "All models are now visible": "Semua model kini kelihatan", "All models deleted successfully": "Semua model telah dipadamkan dengan berjaya", @@ -272,6 +275,7 @@ "Bypass Web Loader": "Langkau Pemuat Web", "Cache Base Model List": "Senarai Model Asas Cache", "Calendar": "Kalendar", + "Calendars": "", "Call": "Hubungi", "Call feature is not supported when using Web STT engine": "Ciri panggilan tidak disokong apabila menggunakan enjin Web STT", "Camera": "Kamera", @@ -522,6 +526,7 @@ "Delete automation?": "", "Delete Chat": "Padam Perbualan", "Delete chat?": "Padam perbualan?", + "Delete Event": "", "Delete File": "Padam Fail", "Delete folder?": "Padam folder?", "Delete function?": "Padam fungsi?", @@ -828,6 +833,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Ralat: Model dengan ID '{{modelId}}' sudah wujud. Sila pilih ID yang berbeza untuk meneruskan.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Ralat: ID Model tidak boleh kosong. Sila masukkan ID yang sah untuk meneruskan.", "Evaluations": "Penilaian", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Kunci API Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Example: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Contoh: SEMUA", @@ -1197,6 +1206,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Hadkan pertanyaan carian serentak. 0 = tanpa had (lalai). Tetapkan kepada 1 untuk pelaksanaan berurutan (disyorkan untuk API dengan had kadar ketat seperti peringkat percuma Brave).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Mengehadkan jumlah permintaan pembenaman serentak. Tetapkan kepada 0 untuk tanpa had.", "List": "Senarai", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Mendengar...", "Live": "Langsung", "Llama.cpp": "Llama.cpp", @@ -1207,6 +1217,7 @@ "local": "tempatan", "Local": "Tempatan", "Local Task Model": "Model Tugas Tempatan", + "Location": "", "Location access not allowed": "Akses lokasi tidak dibenarkan", "Lost": "Hilang", "Low": "Rendah", @@ -1316,6 +1327,7 @@ "Models Sharing": "Perkongsian Model", "Mojeek": "Mojeek", "Mojeek Search API Key": "Kunci API Pencarian Mojeek", + "Month": "", "Monthly": "", "More": "Lagi", "More Concise": "Lebih Ringkas", @@ -1334,6 +1346,7 @@ "New Automation": "", "New Button": "Butang Baru", "New Chat": "Perbualan Baru", + "New Event": "", "New File": "Fail Baru", "New Folder": "Folder Baru", "New Function": "Fungsi Baru", @@ -2011,6 +2024,7 @@ "Title cannot be an empty string.": "Tajuk tidak boleh menjadi rentetan kosong", "Title Generation": "Penjanaan Tajuk", "Title Generation Prompt": "Arahan Penjanaan Tajuk", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Untuk mengakses nama model yang tersedia untuk dimuat turun,", "To access the GGUF models available for downloading,": "Untuk mengakses model GGUF yang tersedia untuk dimuat turun,", @@ -2181,6 +2195,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI akan membuat permintaan ke \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI akan membuat permintaan ke \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI akan membuat permintaan ke \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Apa yang ingin anda capai?", "What are you working on?": "Apa yang sedang anda kerjakan?", @@ -2188,6 +2203,7 @@ "What is shared:": "Apa yang dikongsi:", "What's New in": "Apakah yang terbaru dalam", "What's on your mind?": "Apa yang terlintas di fikiran anda?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Apabila didayakan, model akan bertindak balas kepada setiap mesej sembang secara masa nyata, menjana respons sebaik sahaja pengguna menghantar mesej. Mod ini berguna untuk aplikasi sembang langsung, tetapi mungkin menjejaskan prestasi pada perkakasan yang lebih perlahan.", "wherever you are": "di mana pun anda berada", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Sama ada untuk memisahkan output mengikut halaman. Setiap halaman akan dipisahkan oleh garis mendatar dan nombor halaman. Lalai kepada False.", diff --git a/src/lib/i18n/locales/nb-NO/translation.json b/src/lib/i18n/locales/nb-NO/translation.json index 58c2e8331c..ebfff87340 100644 --- a/src/lib/i18n/locales/nb-NO/translation.json +++ b/src/lib/i18n/locales/nb-NO/translation.json @@ -73,9 +73,11 @@ "Add content here": "Legg til innhold her", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Legg til filer", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Legg til minne", @@ -111,6 +113,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Alle modeller er slettet", @@ -273,6 +276,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "Kalender", + "Calendars": "", "Call": "Ring", "Call feature is not supported when using Web STT engine": "Ringefunksjonen støttes ikke når du bruker Web STT-motoren", "Camera": "Kamera", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "Slett chat", "Delete chat?": "Slette chat?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Slette mappe?", "Delete function?": "Slette funksjon?", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Vurderinger", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "API-nøkkel for Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Eksempel: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Eksempel: ALL", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Lytter ...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1208,6 +1218,7 @@ "local": "", "Local": "Lokal", "Local Task Model": "", + "Location": "", "Location access not allowed": "Tilgang til lokasjon er ikke tillatt", "Lost": "Tapt", "Low": "", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "API-nøekkel for Mojeek Search", + "Month": "", "Monthly": "", "More": "Mer", "More Concise": "", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "", "New Chat": "Ny chat", + "New Event": "", "New File": "", "New Folder": "Ny mappe", "New Function": "", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "Tittel kan ikke være en tom streng.", "Title Generation": "Genering av tittel", "Title Generation Prompt": "Ledetekst for tittelgenerering", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Hvis du vil ha tilgang til modellnavn tilgjengelige for nedlasting,", "To access the GGUF models available for downloading,": "Hvis du vil ha tilgang til GGUF-modellene tilgjengelige for nedlasting,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI vil rette forespørsler til \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI vil rette forespørsler til \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Hva prøver du å oppnå?", "What are you working on?": "Hva jobber du på nå?", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "Hva er nytt i", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Hvis denne modusen er aktivert, svarer modellen på alle chattemeldinger i sanntid, og genererer et svar så snart brukeren sender en melding. Denne modusen er nyttig for live chat-applikasjoner, men kan påvirke ytelsen på tregere maskinvare.", "wherever you are": "uansett hvor du er", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/nl-NL/translation.json b/src/lib/i18n/locales/nl-NL/translation.json index 6a6a3f6b37..3458ccf314 100644 --- a/src/lib/i18n/locales/nl-NL/translation.json +++ b/src/lib/i18n/locales/nl-NL/translation.json @@ -73,9 +73,11 @@ "Add content here": "Voeg hier content toe", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Voeg bestanden toe", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Voeg geheugen toe", @@ -111,6 +113,7 @@ "AI": "", "All": "Alle", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Alle modellen zijn succesvol verwijderd", @@ -273,6 +276,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "Agenda", + "Calendars": "", "Call": "Oproep", "Call feature is not supported when using Web STT engine": "Belfunctie wordt niet ondersteund bij gebruik van de Web STT engine", "Camera": "Camera", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "Verwijder chat", "Delete chat?": "Verwijder chat?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Verwijder map?", "Delete function?": "Verwijder functie?", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Beoordelingen", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API-sleutel", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Voorbeeld: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Voorbeeld: ALL", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Aan het luisteren...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1208,6 +1218,7 @@ "local": "", "Local": "Lokaal", "Local Task Model": "", + "Location": "", "Location access not allowed": "Locatietoegang niet toegestaan", "Lost": "Verloren", "Low": "", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API-sleutel", + "Month": "", "Monthly": "", "More": "Meer", "More Concise": "", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "", "New Chat": "Nieuwe Chat", + "New Event": "", "New File": "", "New Folder": "Nieuwe map", "New Function": "", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "Titel kan niet leeg zijn.", "Title Generation": "Titelgeneratie", "Title Generation Prompt": "Titel Generatie Prompt", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Om de beschikbare modelnamen voor downloaden te openen,", "To access the GGUF models available for downloading,": "Om toegang te krijgen tot de GGUF-modellen die beschikbaar zijn voor downloaden,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI zal verzoeken doen aan \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI zal verzoeken doen aan \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Wat probeer je te bereiken?", "What are you working on?": "Waar werk je aan?", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "Wat is nieuw in", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Als dit is ingeschakeld, reageert het model op elk chatbericht in real-time, waarbij een reactie wordt gegenereerd zodra de gebruiker een bericht stuurt. Deze modus is handig voor live chat-toepassingen, maar kan de prestaties op langzamere hardware beïnvloeden.", "wherever you are": "waar je ook bent", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/pa-IN/translation.json b/src/lib/i18n/locales/pa-IN/translation.json index b29d9f3b42..c6d006cb1a 100644 --- a/src/lib/i18n/locales/pa-IN/translation.json +++ b/src/lib/i18n/locales/pa-IN/translation.json @@ -73,9 +73,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "ਫਾਈਲਾਂ ਸ਼ਾਮਲ ਕਰੋ", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "ਮਿਹਾਨ ਸ਼ਾਮਲ ਕਰੋ", @@ -111,6 +113,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -273,6 +276,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", "Camera": "", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "ਗੱਲਬਾਤ ਮਿਟਾਓ", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "", "Live": "", "Llama.cpp": "", @@ -1208,6 +1218,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "ਹੋਰ", "More Concise": "", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "", "New Chat": "ਨਵੀਂ ਗੱਲਬਾਤ", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "ਸਿਰਲੇਖ ਖਾਲੀ ਸਤਰ ਨਹੀਂ ਹੋ ਸਕਦਾ।", "Title Generation": "", "Title Generation Prompt": "ਸਿਰਲੇਖ ਜਨਰੇਸ਼ਨ ਪ੍ਰੰਪਟ", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "ਡਾਊਨਲੋਡ ਕਰਨ ਲਈ ਉਪਲਬਧ ਮਾਡਲ ਨਾਮਾਂ ਤੱਕ ਪਹੁੰਚਣ ਲਈ,", "To access the GGUF models available for downloading,": "ਡਾਊਨਲੋਡ ਕਰਨ ਲਈ ਉਪਲਬਧ GGUF ਮਾਡਲਾਂ ਤੱਕ ਪਹੁੰਚਣ ਲਈ,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "ਨਵਾਂ ਕੀ ਹੈ", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/pl-PL/translation.json b/src/lib/i18n/locales/pl-PL/translation.json index 3d376b4761..1dff552813 100644 --- a/src/lib/i18n/locales/pl-PL/translation.json +++ b/src/lib/i18n/locales/pl-PL/translation.json @@ -75,9 +75,11 @@ "Add content here": "Dodaj tutaj treść", "Add Custom Parameter": "Dodaj parametr niestandardowy", "Add Custom Prompt": "Dodaj niestandardowy prompt", + "Add description": "", "Add Details": "Dodaj szczegóły", "Add Files": "Dodaj pliki", "Add Image": "", + "Add location": "", "Add Member": "Dodaj członka", "Add Members": "Dodaj członków", "Add Memory": "Dodaj wpis do pamięci", @@ -113,6 +115,7 @@ "AI": "AI", "All": "Wszystkie", "All chats have been unarchived.": "Wszystkie czaty zostały przywrócone.", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Wszystkie modele zostały pomyślnie usunięte.", @@ -275,6 +278,7 @@ "Bypass Web Loader": "Pomiń Web Loader", "Cache Base Model List": "Cachuj listę modeli bazowych", "Calendar": "Kalendarz", + "Calendars": "", "Call": "Rozmowa", "Call feature is not supported when using Web STT engine": "Funkcja rozmowy nie jest obsługiwana przy użyciu przeglądarkowego silnika STT", "Camera": "Kamera", @@ -525,6 +529,7 @@ "Delete automation?": "", "Delete Chat": "Usuń czat", "Delete chat?": "Usunąć czat?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Usunąć folder?", "Delete function?": "Usunąć funkcję?", @@ -831,6 +836,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Błąd: Model o ID '{{modelId}}' już istnieje. Wybierz inne ID.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Błąd: ID modelu nie może być puste. Wprowadź poprawne ID.", "Evaluations": "Ewaluacje", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Klucz API Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Przykład: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Przykład: ALL", @@ -1200,6 +1209,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Limit jednoczesnych zapytań. 0 = brak (domyślnie). Ustaw 1 dla sekwencyjnego wykonywania (zalecane dla darmowych API np. Brave).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "Lista", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Słucham...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1210,6 +1220,7 @@ "local": "lokalny", "Local": "Lokalny", "Local Task Model": "Lokalny Model Zadaniowy", + "Location": "", "Location access not allowed": "Brak dostępu do lokalizacji", "Lost": "Przegrano", "Low": "Niski", @@ -1319,6 +1330,7 @@ "Models Sharing": "Udostępnianie modeli", "Mojeek": "Mojeek", "Mojeek Search API Key": "Klucz API Mojeek Search", + "Month": "", "Monthly": "", "More": "Więcej", "More Concise": "Bardziej zwięzły", @@ -1337,6 +1349,7 @@ "New Automation": "", "New Button": "Nowy przycisk", "New Chat": "Nowy czat", + "New Event": "", "New File": "", "New Folder": "Nowy folder", "New Function": "Nowa funkcja", @@ -2017,6 +2030,7 @@ "Title cannot be an empty string.": "Tytuł nie może być pusty.", "Title Generation": "Generowanie tytułu", "Title Generation Prompt": "Prompt generowania tytułu", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Aby zobaczyć nazwy modeli do pobrania,", "To access the GGUF models available for downloading,": "Aby zobaczyć modele GGUF do pobrania,", @@ -2187,6 +2201,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI będzie wysyłać żądania do \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI będzie wysyłać żądania do \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI będzie wysyłać żądania do \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Co chcesz osiągnąć?", "What are you working on?": "Nad czym pracujesz?", @@ -2194,6 +2209,7 @@ "What is shared:": "Co jest udostępniane:", "What's New in": "Co nowego w", "What's on your mind?": "O czym myślisz?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Gdy włączone, model odpowiada w czasie rzeczywistym. Tryb przydatny w czacie na żywo, ale może obciążać słabszy sprzęt.", "wherever you are": "gdziekolwiek jesteś", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Określa, czy wyniki mają być stronicowane. Strony są oddzielone linią i numerem. Domyślnie wyłączone.", diff --git a/src/lib/i18n/locales/pt-BR/translation.json b/src/lib/i18n/locales/pt-BR/translation.json index 89c06187d1..0954c0a91a 100644 --- a/src/lib/i18n/locales/pt-BR/translation.json +++ b/src/lib/i18n/locales/pt-BR/translation.json @@ -48,7 +48,7 @@ "Access Control": "Controle de Acesso", "Access Grants": "Concessões de Acesso", "Access List": "Lista de acesso", - "Access updated": "", + "Access updated": "Acesso atualizado", "Accessible to all users": "Acessível para todos os usuários", "Account": "Conta", "Account Activation Pending": "Ativação da Conta Pendente", @@ -74,9 +74,11 @@ "Add content here": "Adicionar conteúdo aqui", "Add Custom Parameter": "Adicionar parâmetro personalizado", "Add Custom Prompt": "Adicionar prompt personalizado", + "Add description": "", "Add Details": "Adicionar detalhes", "Add Files": "Adicionar Arquivos", "Add Image": "Adicionar imagem", + "Add location": "", "Add Member": "Adicionar membro", "Add Members": "Adicionar membros", "Add Memory": "Adicionar Memória", @@ -112,6 +114,7 @@ "AI": "IA", "All": "Tudo", "All chats have been unarchived.": "Todos os chats foram desarquivados.", + "All day": "", "All models are now hidden": "Todos os modelos estão agora ocultos", "All models are now visible": "Todos os modelos estão agora visíveis", "All models deleted successfully": "Todos os modelos foram excluídos com sucesso", @@ -274,6 +277,7 @@ "Bypass Web Loader": "Ignorar carregador da Web", "Cache Base Model List": "Lista de modelos base de cache", "Calendar": "Calendário", + "Calendars": "", "Call": "Chamada", "Call feature is not supported when using Web STT engine": "O recurso de chamada não é suportado ao usar o mecanismo Web STT", "Camera": "Câmera", @@ -441,7 +445,7 @@ "Copy Last Response": "Copiar última resposta", "Copy link": "Copiar link", "Copy Link": "Copiar Link", - "Copy Path": "", + "Copy Path": "Copiar caminho", "Copy Prompt": "Copiar prompt", "Copy Share Link": "Copiar link de compartilhamento", "Copy to clipboard": "Copiar para a área de transferência", @@ -524,6 +528,7 @@ "Delete automation?": "Excluir automação?", "Delete Chat": "Excluir Chat", "Delete chat?": "Excluir chat?", + "Delete Event": "", "Delete File": "Excluir arquivo", "Delete folder?": "Excluir pasta?", "Delete function?": "Excluir função?", @@ -830,6 +835,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Erro: Já existe um modelo com o ID '{{modelId}}'. Selecione um ID diferente para prosseguir.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Erro: O ID do modelo não pode estar vazio. Insira um ID válido para prosseguir.", "Evaluations": "Avaliações", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Chave da API Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Exemplo: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Exemplo: ALL", @@ -1199,6 +1208,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Limitar consultas de pesquisa simultâneas. 0 = ilimitado (padrão). Defina como 1 para execução sequencial (recomendado para APIs com limites de taxa rígidos, como o nível gratuito do Brave).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Limita o número de solicitações simultâneas de embedding. Defina como 0 para ilimitado.", "List": "Lista", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Escutando...", "Live": "Ao vivo", "Llama.cpp": "Llama.cpp", @@ -1209,6 +1219,7 @@ "local": "local", "Local": "Local", "Local Task Model": "Modelo de Tarefa Local", + "Location": "", "Location access not allowed": "Acesso ao local não permitido", "Lost": "Perdeu", "Low": "Baixo", @@ -1276,7 +1287,7 @@ "Model": "Modelo", "Model '{{modelName}}' has been successfully downloaded.": "Modelo '{{modelName}}' foi baixado com sucesso.", "Model '{{modelTag}}' is already in queue for downloading.": "Modelo '{{modelTag}}' já está na fila para download.", - "Model {{modelId}} not found": "", + "Model {{modelId}} not found": "Modelo {{modelId}} não encontrado", "Model {{modelName}} deleted successfully": "Modelo {{modelName}} excluído com sucesso", "Model {{modelName}} is not vision capable": "Modelo {{modelName}} não é capaz de visão", "Model {{name}} is now {{status}}": "Modelo {{name}} está agora {{status}}", @@ -1284,7 +1295,7 @@ "Model {{name}} is now visible": "O modelo {{name}} agora está visível", "Model accepts file inputs": "O modelo aceita entradas de arquivo", "Model accepts image inputs": "Modelo aceita entradas de imagens", - "Model can access Open Terminal for command execution and file management": "", + "Model can access Open Terminal for command execution and file management": "O modelo pode acessar o Open Terminal para execução de comandos e gerenciamento de arquivos", "Model can execute code and perform calculations": "O modelo pode executar código e realizar cálculos", "Model can generate images based on text prompts": "O modelo pode gerar imagens com base em prompts de texto", "Model can search the web for information": "O modelo pode pesquisar informações na web", @@ -1318,6 +1329,7 @@ "Models Sharing": "Compartilhamento de Modelos", "Mojeek": "Mojeek", "Mojeek Search API Key": "Chave de API Mojeek Search", + "Month": "", "Monthly": "Mensal", "More": "Mais", "More Concise": "Mais conciso", @@ -1336,6 +1348,7 @@ "New Automation": "Nova Automação", "New Button": "Novo Botão", "New Chat": "Novo Chat", + "New Event": "", "New File": "Novo Arquivo", "New Folder": "Nova Pasta", "New Function": "Nova Função", @@ -1505,7 +1518,7 @@ "Password": "Senha", "Passwords do not match.": "As senhas não coincidem.", "Paste Large Text as File": "Cole Textos Longos como Arquivo", - "Path copied": "", + "Path copied": "Caminho copiado", "Paused": "Em pausa", "PDF document (.pdf)": "Documento PDF (.pdf)", "PDF Extract Images (OCR)": "Extrair Imagens do PDF (OCR)", @@ -1654,7 +1667,7 @@ "Reply to thread...": "Responder ao tópico...", "Replying to {{NAME}}": "Respondendo para {{NAME}}", "required": "obrigatório", - "Reranking Batch Size": "", + "Reranking Batch Size": "Tamanho do lote de reclassificação", "Reranking Engine": "Motor de Reclassificação", "Reranking Model": "Modelo de Reclassificação", "Reset": "Redefinir", @@ -2015,6 +2028,7 @@ "Title cannot be an empty string.": "O Título não pode ser uma string vazia.", "Title Generation": "Geração de Títulos", "Title Generation Prompt": "Prompt de Geração de Título", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Para acessar os nomes de modelos disponíveis para download,", "To access the GGUF models available for downloading,": "Para acessar os modelos GGUF disponíveis para download,", @@ -2185,6 +2199,7 @@ "WebUI will make requests to \"{{url}}\"": "A WebUI fará requisições para \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "A WebUI fará requisições para \"{{url}}/api/chat\".", "WebUI will make requests to \"{{url}}/chat/completions\"": "A WebUI fará requisições para \"{{url}}/chat/completions\".", + "Week": "", "Weekly": "Semanal", "What are you trying to achieve?": "O que está tentando alcançar?", "What are you working on?": "No que está trabalhando?", @@ -2192,6 +2207,7 @@ "What is shared:": "O que é compartilhado", "What's New in": "O que há de novo em", "What's on your mind?": "O que você tem em mente?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Quando habilitado, o modelo responderá a cada mensagem de chat em tempo real, gerando uma resposta assim que o usuário enviar uma mensagem. Este modo é útil para aplicativos de chat ao vivo, mas pode impactar o desempenho em hardware mais lento.", "wherever you are": "onde quer que você esteja.", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Se a saída deve ser paginada. Cada página será separada por uma régua horizontal e um número de página. O padrão é Falso.", diff --git a/src/lib/i18n/locales/pt-PT/translation.json b/src/lib/i18n/locales/pt-PT/translation.json index ced26ce5d6..c8f23d1dea 100644 --- a/src/lib/i18n/locales/pt-PT/translation.json +++ b/src/lib/i18n/locales/pt-PT/translation.json @@ -74,9 +74,11 @@ "Add content here": "Adicionar conteúdo aqui", "Add Custom Parameter": "Adicionar Parâmetro Personalizado", "Add Custom Prompt": "Adicionar Prompt Personalizado", + "Add description": "", "Add Details": "Adicionar Detalhes", "Add Files": "Adicionar Ficheiros", "Add Image": "Adicionar Imagem", + "Add location": "", "Add Member": "Adicionar Membro", "Add Members": "Adicionar Membros", "Add Memory": "Adicionar memória", @@ -112,6 +114,7 @@ "AI": "IA", "All": "Todos", "All chats have been unarchived.": "Todos as conversas foram desarquivadas.", + "All day": "", "All models are now hidden": "Todos os modelos estão agora ocultos", "All models are now visible": "Todos os modelos estão agora visíveis", "All models deleted successfully": "Todos os modelos foram eliminados com sucesso", @@ -274,6 +277,7 @@ "Bypass Web Loader": "Ignorar Carregador Web", "Cache Base Model List": "Cache da Lista de Modelos Base", "Calendar": "Calendário", + "Calendars": "", "Call": "Chamar", "Call feature is not supported when using Web STT engine": "A funcionalide de Chamar não é suportada quando usa um motor Web STT", "Camera": "Câmara", @@ -524,6 +528,7 @@ "Delete automation?": "", "Delete Chat": "Apagar Conversa", "Delete chat?": "Apagar conversa?", + "Delete Event": "", "Delete File": "Apagar ficheiro", "Delete folder?": "Apagar pasta", "Delete function?": "Apagar função", @@ -830,6 +835,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Erro: Um modelo com o ID '{{modelId}}' já existe. Por favor, selecione um ID diferente para continuar.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Erro: O ID do modelo não pode estar vazio. Por favor insira o ID válido para continuar.", "Evaluations": "Avaliações", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Chave da API Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Exemplo: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "", @@ -1199,6 +1208,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Limitar consultas de pesquisa simultâneas. 0 = ilimitado (padrão). Defina como 1 para execução sequencial (recomendado para APIs com limites de taxa rigorosos, como o nível gratuito do Brave).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Limita o número de solicitações de incorporação simultâneas. Defina como 0 para ilimitado.", "List": "Lista", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "A ouvir...", "Live": "Ao vivo", "Llama.cpp": "Llama.cpp", @@ -1209,6 +1219,7 @@ "local": "local", "Local": "Local", "Local Task Model": "Modelo de Tarefa Local", + "Location": "", "Location access not allowed": "Acesso à localização não permitido", "Lost": "Perdido", "Low": "Baixo", @@ -1318,6 +1329,7 @@ "Models Sharing": "Partilha de Modelos", "Mojeek": "Mojeek", "Mojeek Search API Key": "Chave API de Pesquisa Mojeek", + "Month": "", "Monthly": "", "More": "Mais", "More Concise": "Mais Conciso", @@ -1336,6 +1348,7 @@ "New Automation": "", "New Button": "Novo Botão", "New Chat": "Nova Conversa", + "New Event": "", "New File": "Novo Ficheiro", "New Folder": "Nova Pasta", "New Function": "Nova Função", @@ -2015,6 +2028,7 @@ "Title cannot be an empty string.": "Título não pode ser uma string vazia.", "Title Generation": "Geração de Título", "Title Generation Prompt": "Prompt de Geração de Título", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Para aceder aos nomes de modelo disponíveis para descarregar,", "To access the GGUF models available for downloading,": "Para aceder aos modelos GGUF disponíveis para descarregar,", @@ -2185,6 +2199,7 @@ "WebUI will make requests to \"{{url}}\"": "O WebUI fará solicitações para \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "O WebUI fará solicitações para \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "O WebUI fará solicitações para \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "O que você está tentando alcançar?", "What are you working on?": "Em que você está trabalhando?", @@ -2192,6 +2207,7 @@ "What is shared:": "O que é compartilhado:", "What's New in": "O que há de novo em", "What's on your mind?": "O que está A pensaR?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Quando ativado, o modelo responderá a cada mensagem do chat em tempo real, gerando uma resposta assim que o utilizador enviar uma mensagem. Este modo é útil para aplicações de chat ao vivo, mas pode impactar o desempenho em hardware mais lento.", "wherever you are": "onde quer que esteja", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Se deve paginar a saída. Cada página será separada por uma linha horizontal e número de página. Padrão é Falso.", diff --git a/src/lib/i18n/locales/ro-RO/translation.json b/src/lib/i18n/locales/ro-RO/translation.json index 3b4e8a4475..0215a6eacc 100644 --- a/src/lib/i18n/locales/ro-RO/translation.json +++ b/src/lib/i18n/locales/ro-RO/translation.json @@ -74,9 +74,11 @@ "Add content here": "Adăugați conținut aici", "Add Custom Parameter": "Adaugă parametru personalizat", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Adaugă fișiere", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Adaugă memorie", @@ -112,6 +114,7 @@ "AI": "", "All": "Toate", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Toate modelele au fost șterse cu succes", @@ -274,6 +277,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendars": "", "Call": "Apel", "Call feature is not supported when using Web STT engine": "Funcția de apel nu este suportată când se utilizează motorul Web STT", "Camera": "Cameră", @@ -524,6 +528,7 @@ "Delete automation?": "", "Delete Chat": "Șterge Conversația", "Delete chat?": "Șterge conversația?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Ștergeți folderul?", "Delete function?": "Șterge funcția?", @@ -830,6 +835,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Evaluări", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -1199,6 +1208,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Ascult...", "Live": "", "Llama.cpp": "", @@ -1209,6 +1219,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "Pierdut", "Low": "", @@ -1318,6 +1329,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "Mai multe", "More Concise": "", @@ -1336,6 +1348,7 @@ "New Automation": "", "New Button": "", "New Chat": "Conversație Nouă", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -2015,6 +2028,7 @@ "Title cannot be an empty string.": "Titlul nu poate fi un șir gol.", "Title Generation": "", "Title Generation Prompt": "Prompt de Generare a Titlului", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "Pentru a accesa numele modelelor disponibile pentru descărcare,", "To access the GGUF models available for downloading,": "Pentru a accesa modelele GGUF disponibile pentru descărcare,", @@ -2185,6 +2199,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2192,6 +2207,7 @@ "What is shared:": "", "What's New in": "Ce e Nou în", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/ru-RU/translation.json b/src/lib/i18n/locales/ru-RU/translation.json index 0f48a63c1e..15663aecc0 100644 --- a/src/lib/i18n/locales/ru-RU/translation.json +++ b/src/lib/i18n/locales/ru-RU/translation.json @@ -75,9 +75,11 @@ "Add content here": "Добавить контент сюда", "Add Custom Parameter": "Добавить пользовательский параметр", "Add Custom Prompt": "Добавить пользовательский запрос", + "Add description": "", "Add Details": "Добавить детали", "Add Files": "Добавить файлы", "Add Image": "Добавить изображение", + "Add location": "", "Add Member": "Добавить участника", "Add Members": "Добавить участников", "Add Memory": "Добавить воспоминание", @@ -113,6 +115,7 @@ "AI": "AI", "All": "Все", "All chats have been unarchived.": "Все чаты были разархивированы.", + "All day": "", "All models are now hidden": "Все модели скрыты", "All models are now visible": "Все модели видимы", "All models deleted successfully": "Все модели успешно удалены", @@ -275,6 +278,7 @@ "Bypass Web Loader": "Обход веб-загрузчика", "Cache Base Model List": "Кэшировать список базовых моделей", "Calendar": "Календарь", + "Calendars": "", "Call": "Вызов", "Call feature is not supported when using Web STT engine": "Функция вызова не поддерживается при использовании Web STT (распознавание речи) движка", "Camera": "Камера", @@ -525,6 +529,7 @@ "Delete automation?": "", "Delete Chat": "Удалить Чат", "Delete chat?": "Удалить чат?", + "Delete Event": "", "Delete File": "Удалить файл", "Delete folder?": "Удалить папку?", "Delete function?": "Удалить функцию?", @@ -831,6 +836,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Ошибка: Модель с ID '{{modelId}}' уже существует. Пожалуйста, выберите другой ID для продолжения.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Ошибка: ID модели не может быть пустым. Пожалуйста, введите корректный ID для продолжения.", "Evaluations": "Оценки", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Ключ API для Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Например: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Например: ALL", @@ -1200,6 +1209,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Лимит параллельных поисковых запросов. 0 = без ограничений (по умолчанию). Установите 1 для последовательного выполнения (рекомендуется для API со строгими лимитами, например, бесплатный тариф Brave).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Ограничивает число параллельных запросов эмбеддингов. 0 — без ограничений.", "List": "Список", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Слушаю...", "Live": "Активно", "Llama.cpp": "Llama.cpp", @@ -1210,6 +1220,7 @@ "local": "локально", "Local": "Локально", "Local Task Model": "Модель локальной задачи", + "Location": "", "Location access not allowed": "Доступ к местоположению запрещен", "Lost": "Поражение", "Low": "Низкий", @@ -1319,6 +1330,7 @@ "Models Sharing": "Общий доступ к моделям", "Mojeek": "Mojeek", "Mojeek Search API Key": "Ключ API для поиска Mojeek", + "Month": "", "Monthly": "", "More": "Больше", "More Concise": "Более кратко", @@ -1337,6 +1349,7 @@ "New Automation": "", "New Button": "Новая кнопка", "New Chat": "Новый чат", + "New Event": "", "New File": "Новый файл", "New Folder": "Новая папка", "New Function": "Новая функция", @@ -2017,6 +2030,7 @@ "Title cannot be an empty string.": "Заголовок не может быть пустой строкой.", "Title Generation": "Генерация заголовка", "Title Generation Prompt": "Промпт для генерации заголовка", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Чтобы получить доступ к доступным для загрузки названиям моделей,", "To access the GGUF models available for downloading,": "Чтобы получить доступ к моделям GGUF, доступным для загрузки,", @@ -2187,6 +2201,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI будет отправлять запросы к \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI будет отправлять запросы к \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI будет отправлять запросы к \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Чего вы пытаетесь достичь?", "What are you working on?": "Над чем вы работаете?", @@ -2194,6 +2209,7 @@ "What is shared:": "Что передаётся:", "What's New in": "Что нового в", "What's on your mind?": "О чём хотите поговорить?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Если эта функция включена, модель будет отвечать на каждое сообщение чата в режиме реального времени, генерируя ответ, как только пользователь отправит сообщение. Этот режим полезен для приложений живого чата, но может повлиять на производительность на более медленном оборудовании.", "wherever you are": "где бы вы ни были", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Следует ли разбивать выходные данные на страницы. Каждая страница будет разделена горизонтальной линией и номером страницы. По умолчанию установлено значение Выкл.", diff --git a/src/lib/i18n/locales/sk-SK/translation.json b/src/lib/i18n/locales/sk-SK/translation.json index 1bb253b84d..74d16d847c 100644 --- a/src/lib/i18n/locales/sk-SK/translation.json +++ b/src/lib/i18n/locales/sk-SK/translation.json @@ -75,9 +75,11 @@ "Add content here": "Pridať obsah sem", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Pridať súbory", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Pridať pamäť", @@ -113,6 +115,7 @@ "AI": "", "All": "Všetky", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Všetky modely úspešne odstránené", @@ -275,6 +278,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendars": "", "Call": "Volanie", "Call feature is not supported when using Web STT engine": "Funkcia volania nie je podporovaná pri použití Web STT engine.", "Camera": "Kamera", @@ -525,6 +529,7 @@ "Delete automation?": "", "Delete Chat": "Odstrániť chat", "Delete chat?": "Odstrániť konverzáciu?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Odstrániť priečinok?", "Delete function?": "Funkcia na odstránenie?", @@ -831,6 +836,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Hodnotenia", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -1200,6 +1209,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Počúvanie...", "Live": "", "Llama.cpp": "", @@ -1210,6 +1220,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "Stratený", "Low": "", @@ -1319,6 +1330,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "Viac", "More Concise": "", @@ -1337,6 +1349,7 @@ "New Automation": "", "New Button": "", "New Chat": "Nový chat", + "New Event": "", "New File": "", "New Folder": "Nový priečinok", "New Function": "", @@ -2017,6 +2030,7 @@ "Title cannot be an empty string.": "Názov nemôže byť prázdny reťazec.", "Title Generation": "", "Title Generation Prompt": "Generovanie názvu promptu", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "Pre získanie dostupných názvov modelov na stiahnutie,", "To access the GGUF models available for downloading,": "Pre prístup k modelom GGUF dostupným na stiahnutie,", @@ -2187,6 +2201,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Čo sa snažíte dosiahnuť?", "What are you working on?": "Na čom pracujete?", @@ -2194,6 +2209,7 @@ "What is shared:": "", "What's New in": "Čo je nové v", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "kdekoľvek ste", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/sr-RS/translation.json b/src/lib/i18n/locales/sr-RS/translation.json index d0eb329904..fd5e72e1fb 100644 --- a/src/lib/i18n/locales/sr-RS/translation.json +++ b/src/lib/i18n/locales/sr-RS/translation.json @@ -74,9 +74,11 @@ "Add content here": "Додај садржај овде", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Додај датотеке", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Додај сећање", @@ -112,6 +114,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Сви модели су успешно обрисани", @@ -274,6 +277,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendars": "", "Call": "Позив", "Call feature is not supported when using Web STT engine": "", "Camera": "Камера", @@ -524,6 +528,7 @@ "Delete automation?": "", "Delete Chat": "Обриши ћаскање", "Delete chat?": "Обрисати ћаскање?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Обрисати фасциклу?", "Delete function?": "Обрисати функцију?", @@ -830,6 +835,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Процењивања", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -1199,6 +1208,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Слушам...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1209,6 +1219,7 @@ "local": "", "Local": "Локално", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "Пораза", "Low": "", @@ -1318,6 +1329,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "Више", "More Concise": "", @@ -1336,6 +1348,7 @@ "New Automation": "", "New Button": "", "New Chat": "Ново ћаскање", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -2015,6 +2028,7 @@ "Title cannot be an empty string.": "Наслов не може бити празан низ.", "Title Generation": "", "Title Generation Prompt": "Упит за стварање наслова", + "Title is required": "", "TLS": "ТЛС", "To access the available model names for downloading,": "Да бисте приступили доступним именима модела за преузимање,", "To access the GGUF models available for downloading,": "Да бисте приступили GGUF моделима доступним за преузимање,", @@ -2185,6 +2199,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2192,6 +2207,7 @@ "What is shared:": "", "What's New in": "Шта је ново у", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/sv-SE/translation.json b/src/lib/i18n/locales/sv-SE/translation.json index c49965c7fc..d75b41b928 100644 --- a/src/lib/i18n/locales/sv-SE/translation.json +++ b/src/lib/i18n/locales/sv-SE/translation.json @@ -73,9 +73,11 @@ "Add content here": "Lägg till innehåll här", "Add Custom Parameter": "Lägg till anpassad parameter", "Add Custom Prompt": "", + "Add description": "", "Add Details": "Lägg till information", "Add Files": "Lägg till filer", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Lägg till minne", @@ -111,6 +113,7 @@ "AI": "", "All": "Alla", "All chats have been unarchived.": "Alla konversationer har avarkiverats.", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Alla modeller har raderats framgångsrikt", @@ -273,6 +276,7 @@ "Bypass Web Loader": "Kringgå webbläsare", "Cache Base Model List": "", "Calendar": "Kalender", + "Calendars": "", "Call": "Samtal", "Call feature is not supported when using Web STT engine": "Samtalsfunktionen är inte kompatibel med Web Tal-till-text motor", "Camera": "Kamera", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "Radera chatt", "Delete chat?": "Radera chatt?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Radera mapp?", "Delete function?": "Radera funktion?", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Utvärderingar", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API-nyckel", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Exempel: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Exempel: ALLA", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Lyssnar...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1208,6 +1218,7 @@ "local": "lokal", "Local": "Lokal", "Local Task Model": "Lokal uppgiftsmodell", + "Location": "", "Location access not allowed": "Åtkomst till platsen är inte tillåten", "Lost": "Förlorad", "Low": "Låg", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Mojeek Sök API-nyckel", + "Month": "", "Monthly": "", "More": "Mer", "More Concise": "Mer kortfattat", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "Ny knapp", "New Chat": "Ny chatt", + "New Event": "", "New File": "", "New Folder": "Ny mapp", "New Function": "Ny funktion", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "Titeln får inte vara en tom sträng.", "Title Generation": "Titelgenerering", "Title Generation Prompt": "Instruktion för titelgenerering", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "För att komma åt de tillgängliga modellnamnen för nedladdning,", "To access the GGUF models available for downloading,": "För att komma åt de GGUF-modellerna som finns tillgängliga för nedladdning,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI kommer att göra förfrågningar till \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI kommer att göra förfrågningar till \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI kommer att göra förfrågningar till \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Vad försöker du uppnå?", "What are you working on?": "Var arbetar du med?", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "Vad är nytt i", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "När det här läget är aktiverat svarar modellen på varje chattmeddelande i realtid och genererar ett svar så snart användaren skickar ett meddelande. Det här läget är användbart för livechattar, men kan påverka prestandan på långsammare maskinvara.", "wherever you are": "var du än befinner dig", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Om utdata ska sidnumreras. Varje sida kommer att separeras av en horisontell linje och sidnummer. Standardvärdet är False.", diff --git a/src/lib/i18n/locales/ta-IN/translation.json b/src/lib/i18n/locales/ta-IN/translation.json index c2f4ee4003..8e5af4f6e2 100644 --- a/src/lib/i18n/locales/ta-IN/translation.json +++ b/src/lib/i18n/locales/ta-IN/translation.json @@ -73,9 +73,11 @@ "Add content here": "உள்ளடக்கத்தை இங்கே சேர்க்கவும்", "Add Custom Parameter": "தனிப்பயன் அளவுருவைச் சேர்க்கவும்", "Add Custom Prompt": "தனிப்பயன் வரியில் சேர்க்கவும்", + "Add description": "", "Add Details": "விவரங்களைச் சேர்க்கவும்", "Add Files": "கோப்புகளைச் சேர்க்கவும்", "Add Image": "படத்தைச் சேர்க்கவும்", + "Add location": "", "Add Member": "உறுப்பினரைச் சேர்க்கவும்", "Add Members": "உறுப்பினர்களைச் சேர்க்கவும்", "Add Memory": "நினைவகத்தைச் சேர்க்கவும்", @@ -111,6 +113,7 @@ "AI": "AI", "All": "அனைத்தும்", "All chats have been unarchived.": "அனைத்து அரட்டைகளும் மீட்டெடுக்கப்பட்டன.", + "All day": "", "All models are now hidden": "அனைத்து மாடல்களும் இப்போது மறைக்கப்பட்டுள்ளன", "All models are now visible": "அனைத்து மாடல்களும் இப்போது தெரியும்", "All models deleted successfully": "அனைத்து மாடல்களும் வெற்றிகரமாக நீக்கப்பட்டன", @@ -273,6 +276,7 @@ "Bypass Web Loader": "பைபாஸ் இணைய ஏற்றி", "Cache Base Model List": "கேச் அடிப்படை மாதிரி பட்டியல்", "Calendar": "நாட்காட்டி", + "Calendars": "", "Call": "அழைக்கவும்", "Call feature is not supported when using Web STT engine": "Web STT இன்ஜினைப் பயன்படுத்தும் போது அழைப்பு அம்சம் ஆதரிக்கப்படாது", "Camera": "கேமரா", @@ -523,6 +527,7 @@ "Delete automation?": "தானியக்கத்தை நீக்கவா?", "Delete Chat": "அரட்டையை நீக்கு", "Delete chat?": "அரட்டையை நீக்கவா?", + "Delete Event": "", "Delete File": "கோப்பை நீக்கு", "Delete folder?": "கோப்புறையை நீக்கவா?", "Delete function?": "செயல்பாட்டை நீக்கவா?", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "பிழை: ID '{{modelId}}' உடன் ஒரு மாதிரி ஏற்கனவே உள்ளது. தொடர வேறு ID ஐத் தேர்ந்தெடுக்கவும்.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "பிழை: மாடல் ID காலியாக இருக்க முடியாது. தொடர சரியான ID ஐ உள்ளிடவும்.", "Evaluations": "மதிப்பீடுகள்", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API விசை", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "எடுத்துக்காட்டு: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "எடுத்துக்காட்டு: ALL", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "ஒரே நேரத்தில் தேடல் வினவல்களை வரம்பிடவும். 0 = வரம்பற்றது (இயல்புநிலை). தொடர்ச்சியான செயல்பாட்டிற்கு 1 என அமைக்கவும் (பிரேவ் ஃப்ரீ டையர் போன்ற கடுமையான விகித வரம்புகளைக் கொண்ட API களுக்குப் பரிந்துரைக்கப்படுகிறது).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "ஒரே நேரத்தில் உட்பொதித்தல் கோரிக்கைகளின் எண்ணிக்கையைக் கட்டுப்படுத்துகிறது. வரம்பற்ற 0 என அமைக்கவும்.", "List": "பட்டியல்", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "கேட்கிறது...", "Live": "வாழ்க", "Llama.cpp": "லாமா.சிபிபி", @@ -1208,6 +1218,7 @@ "local": "உள்ளூர்", "Local": "உள்ளூர்", "Local Task Model": "உள்ளூர் பணி மாதிரி", + "Location": "", "Location access not allowed": "இருப்பிட அணுகல் அனுமதிக்கப்படவில்லை", "Lost": "இழந்தது", "Low": "குறைந்த", @@ -1317,6 +1328,7 @@ "Models Sharing": "மாதிரிகள் பகிர்வு", "Mojeek": "மொஜீக்", "Mojeek Search API Key": "Mojeek தேடல் API விசை", + "Month": "", "Monthly": "", "More": "மேலும்", "More Concise": "மேலும் சுருக்கமானது", @@ -1335,6 +1347,7 @@ "New Automation": "புதிய தானியக்கம்", "New Button": "புதிய பொத்தான்", "New Chat": "புதிய அரட்டை", + "New Event": "", "New File": "புதிய கோப்பு", "New Folder": "புதிய கோப்புறை", "New Function": "புதிய செயல்பாடு", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "தலைப்பு வெற்று சரமாக இருக்கக்கூடாது.", "Title Generation": "தலைப்பு தலைமுறை", "Title Generation Prompt": "தலைப்பு உருவாக்கத் தூண்டுதல்", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "பதிவிறக்குவதற்கு கிடைக்கக்கூடிய மாதிரி பெயர்களை அணுக,", "To access the GGUF models available for downloading,": "பதிவிறக்குவதற்கு கிடைக்கும் GGUF மாதிரிகளை அணுக,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI \"{{url}}\" க்கு கோரிக்கைகளை வைக்கும்", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI \"{{url}}/api/chat\" க்கு கோரிக்கைகளை வைக்கும்", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI \"{{url}}/chat/completions\" க்கு கோரிக்கைகளை வைக்கும்", + "Week": "", "Weekly": "", "What are you trying to achieve?": "நீங்கள் எதை அடைய முயற்சிக்கிறீர்கள்?", "What are you working on?": "நீங்கள் என்ன வேலை செய்கிறீர்கள்?", @@ -2190,6 +2205,7 @@ "What is shared:": "என்ன பகிரப்படுகிறது:", "What's New in": "இதில் புதிதாக என்ன இருக்கிறது", "What's on your mind?": "உங்கள் மனதில் என்ன இருக்கிறது?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "இயக்கப்பட்டால், மாடல் ஒவ்வொரு அரட்டை செய்திக்கும் நிகழ்நேரத்தில் பதிலளிக்கும், பயனர் செய்தியை அனுப்பியவுடன் பதிலை உருவாக்கும். நேரடி அரட்டை பயன்பாடுகளுக்கு இந்த பயன்முறை பயனுள்ளதாக இருக்கும், ஆனால் மெதுவான வன்பொருளில் செயல்திறனை பாதிக்கலாம்.", "wherever you are": "நீங்கள் எங்கிருந்தாலும்", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "வெளியீட்டை பக்கமாக்க வேண்டுமா. ஒவ்வொரு பக்கமும் கிடைமட்ட விதி மற்றும் பக்க எண்ணால் பிரிக்கப்படும். இயல்புநிலையிலிருந்து தவறு.", diff --git a/src/lib/i18n/locales/th-TH/translation.json b/src/lib/i18n/locales/th-TH/translation.json index fdcd9b0e26..733bd77d5e 100644 --- a/src/lib/i18n/locales/th-TH/translation.json +++ b/src/lib/i18n/locales/th-TH/translation.json @@ -72,9 +72,11 @@ "Add content here": "เพิ่มเนื้อหาตรงนี้", "Add Custom Parameter": "เพิ่มพารามิเตอร์ที่กำหนดเอง", "Add Custom Prompt": "เพิ่มพรอมต์ที่กำหนดเอง", + "Add description": "", "Add Details": "เพิ่มรายละเอียด", "Add Files": "เพิ่มไฟล์", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "เพิ่มความจำ", @@ -110,6 +112,7 @@ "AI": "AI", "All": "ทั้งหมด", "All chats have been unarchived.": "ยกเลิกการเก็บถาวรการแชททั้งหมดแล้ว", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "ลบโมเดลทั้งหมดเรียบร้อยแล้ว", @@ -272,6 +275,7 @@ "Bypass Web Loader": "ข้ามตัวโหลดเว็บไซต์", "Cache Base Model List": "แคชรายการโมเดลพื้นฐาน", "Calendar": "ปฏิทิน", + "Calendars": "", "Call": "โทร", "Call feature is not supported when using Web STT engine": "ไม่รองรับฟีเจอร์การโทรเมื่อใช้เอนจิน Web STT", "Camera": "กล้อง", @@ -522,6 +526,7 @@ "Delete automation?": "", "Delete Chat": "ลบแชท", "Delete chat?": "ลบแชท?", + "Delete Event": "", "Delete File": "", "Delete folder?": "ลบโฟลเดอร์ใช่หรือไม่?", "Delete function?": "ลบฟังก์ชัน?", @@ -828,6 +833,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "ข้อผิดพลาด: มีโมเดลที่ใช้ ID '{{modelId}}' อยู่แล้ว โปรดเลือก ID อื่นเพื่อดำเนินการต่อ", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "ข้อผิดพลาด: ห้ามปล่อย ID โมเดลว่างไว้ กรุณากรอก ID ที่ถูกต้องเพื่อดำเนินการต่อ", "Evaluations": "การประเมิน", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "API Key ของ Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "ตัวอย่าง: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "ตัวอย่าง: ทั้งหมด", @@ -1197,6 +1206,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "กำลังฟัง...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1207,6 +1217,7 @@ "local": "ภายในเครื่อง", "Local": "ในเครื่อง", "Local Task Model": "โมเดลงานบนเครื่อง", + "Location": "", "Location access not allowed": "ไม่อนุญาตให้เข้าถึงตำแหน่งที่ตั้ง", "Lost": "หาย", "Low": "ต่ำ", @@ -1316,6 +1327,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "API Key สำหรับ Mojeek Search", + "Month": "", "Monthly": "", "More": "เพิ่มเติม", "More Concise": "กระชับมากขึ้น", @@ -1334,6 +1346,7 @@ "New Automation": "", "New Button": "ปุ่มใหม่", "New Chat": "แชทใหม่", + "New Event": "", "New File": "", "New Folder": "โฟลเดอร์ใหม่", "New Function": "ฟังก์ชันใหม่", @@ -2011,6 +2024,7 @@ "Title cannot be an empty string.": "ชื่อเรื่องต้องไม่เป็นสตริงว่าง", "Title Generation": "การสร้างชื่อเรื่อง", "Title Generation Prompt": "พรอมต์สำหรับสร้างชื่อเรื่อง", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "ในการเข้าถึงชื่อโมเดลที่มีให้ดาวน์โหลดนั้น", "To access the GGUF models available for downloading,": "ในการเข้าถึงโมเดล GGUF ที่มีให้ดาวน์โหลดได้", @@ -2181,6 +2195,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI จะส่งคำขอไปยัง \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI จะส่งคำขอไปที่ \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI จะส่งคำขอไปยัง \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "คุณพยายามจะทำอะไร?", "What are you working on?": "คุณกำลังทำอะไรอยู่?", @@ -2188,6 +2203,7 @@ "What is shared:": "", "What's New in": "มีอะไรใหม่ใน", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "เมื่อเปิดใช้งาน โมเดลจะตอบกลับแต่ละข้อความแชทแบบเรียลไทม์ โดยสร้างคำตอบทันทีที่ผู้ใช้ส่งข้อความ โหมดนี้มีประโยชน์สำหรับแอปแชทแบบสด แต่อาจส่งผลต่อประสิทธิภาพบนฮาร์ดแวร์ที่ทำงานช้า", "wherever you are": "ไม่ว่าคุณจะอยู่ที่ไหน", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "ว่าจะแบ่งหน้าผลลัพธ์หรือไม่ แต่ละหน้าจะถูกแยกด้วยเส้นแบ่งแนวนอนและหมายเลขหน้า ค่าเริ่มต้นคือ False", diff --git a/src/lib/i18n/locales/tk-TM/translation.json b/src/lib/i18n/locales/tk-TM/translation.json index a4614b17c7..7fb04a3227 100644 --- a/src/lib/i18n/locales/tk-TM/translation.json +++ b/src/lib/i18n/locales/tk-TM/translation.json @@ -73,9 +73,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Faýllar goş", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Ýat goş", @@ -111,6 +113,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -273,6 +276,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", "Camera": "", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "", "Live": "", "Llama.cpp": "", @@ -1208,6 +1218,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "Has köp", "More Concise": "", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "", "New Chat": "", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "", "Title Generation": "", "Title Generation Prompt": "", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "", "To access the GGUF models available for downloading,": "", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/tr-TR/translation.json b/src/lib/i18n/locales/tr-TR/translation.json index bbe656943f..8d9e63ce85 100644 --- a/src/lib/i18n/locales/tr-TR/translation.json +++ b/src/lib/i18n/locales/tr-TR/translation.json @@ -73,9 +73,11 @@ "Add content here": "Buraya içerik ekleyin", "Add Custom Parameter": "Özel Parametre Ekle", "Add Custom Prompt": "Özel Prompt Ekle", + "Add description": "", "Add Details": "Ayrıntı Ekle", "Add Files": "Dosyalar Ekle", "Add Image": "Görsel Ekle", + "Add location": "", "Add Member": "Üye Ekle", "Add Members": "Üyeleri Ekle", "Add Memory": "Bellek Ekle", @@ -111,6 +113,7 @@ "AI": "Yapay Zeka", "All": "Tüm", "All chats have been unarchived.": "Tüm sohbetler arşivden çıkarıldı.", + "All day": "", "All models are now hidden": "Tüm modeller artık gizli", "All models are now visible": "Tüm modeller artık görünür", "All models deleted successfully": "Tüm modeller başarıyla silindi", @@ -273,6 +276,7 @@ "Bypass Web Loader": "Web Yükleyicisini Atla", "Cache Base Model List": "Temel Model Listesini Önbelleğe Al", "Calendar": "Takvim", + "Calendars": "", "Call": "Arama", "Call feature is not supported when using Web STT engine": "Web STT motoru kullanılırken arama özelliği desteklenmiyor", "Camera": "Kamera", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "Sohbeti Sil", "Delete chat?": "Sohbeti sil?", + "Delete Event": "", "Delete File": "Dosyayı Sil", "Delete folder?": "Klasörü sil?", "Delete function?": "Fonksiyonu sil?", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Hata: '{{modelId}}' ID'sine sahip bir model zaten mevcut. Devam etmek için lütfen farklı bir ID seçin.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Hata: Model ID'si boş olamaz. Devam etmek için lütfen geçerli bir ID girin.", "Evaluations": "Değerlendirmeler", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API Anahtarı", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Örnek: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Örnek: ALL", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Eşzamanlı arama sorgularını sınırla. 0 = sınırsız (varsayılan). Sıralı yürütme için 1 olarak ayarlayın (Brave ücretsiz katman gibi katı oran sınırlarına sahip API'ler için önerilir).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Dinleniyor...", "Live": "", "Llama.cpp": "", @@ -1208,6 +1218,7 @@ "local": "", "Local": "Yerel", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "Kayıp", "Low": "", @@ -1317,6 +1328,7 @@ "Models Sharing": "Model Paylaşımı", "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API Anahtarı", + "Month": "", "Monthly": "", "More": "Daha Fazla", "More Concise": "", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "", "New Chat": "Yeni Sohbet", + "New Event": "", "New File": "", "New Folder": "Yeni Klasör", "New Function": "Yeni Fonksiyon", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "Başlık boş bir dize olamaz.", "Title Generation": "Başlık Oluşturma", "Title Generation Prompt": "Başlık Oluşturma Prompt'u", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "İndirilebilir mevcut model adlarına erişmek için,", "To access the GGUF models available for downloading,": "İndirilebilir mevcut GGUF modellerine erişmek için,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI, \"{{url}}/api/chat\" adresine istek yapacak", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI, \"{{url}}/chat/completions\" adresine istek yapacak", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Ne yapmaya çalışıyorsunuz?", "What are you working on?": "Üzerinde çalıştığınız nedir?", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "Yenilikler:", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Etkinleştirildiğinde, model her sohbet mesajına gerçek zamanlı olarak yanıt verecek ve kullanıcı bir mesaj gönderdiği anda bir yanıt üretecektir. Bu mod canlı sohbet uygulamaları için yararlıdır, ancak daha yavaş donanımlarda performansı etkileyebilir.", "wherever you are": "nerede olursanız olun", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/ug-CN/translation.json b/src/lib/i18n/locales/ug-CN/translation.json index 45745be3c9..ea8c92b507 100644 --- a/src/lib/i18n/locales/ug-CN/translation.json +++ b/src/lib/i18n/locales/ug-CN/translation.json @@ -73,9 +73,11 @@ "Add content here": "مەزمۇننى بۇ يەرگە قوشۇڭ", "Add Custom Parameter": "ئۆزلۈك پارامېتىر قوشۇش", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "ھۆججەتلەر قوشۇش", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "ئەسلەتمە قوشۇش", @@ -111,6 +113,7 @@ "AI": "", "All": "ھەممىسى", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "بارلىق مودېللار مۇۋەپپەقىيەتلىك ئۆچۈرۈلدى", @@ -273,6 +276,7 @@ "Bypass Web Loader": "تور يۈكلىگۈچتىن ئۆتۈپ كېتىش", "Cache Base Model List": "", "Calendar": "كالىندار", + "Calendars": "", "Call": "چاقىرىش", "Call feature is not supported when using Web STT engine": "تور STT ماتورى ئىشلىتىلگەندە چاقىرىش ئىقتىدارى قوللىنىلمايدۇ", "Camera": "كامېرا", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "سۆھبەت ئۆچۈرۈش", "Delete chat?": "سۆھبەت ئۆچۈرەمسىز؟", + "Delete Event": "", "Delete File": "", "Delete folder?": "قىسقۇچ ئۆچۈرەمسىز؟", "Delete function?": "فۇنكسىيە ئۆچۈرەمسىز؟", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "باھالاشلار", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API ئاچقۇچى", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "مەسىلەن: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "مەسىلەن: ALL", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "ئاڭلاۋاتىدۇ...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1208,6 +1218,7 @@ "local": "", "Local": "يەرلىك", "Local Task Model": "يەرلىك ۋەزىپە مودېلى", + "Location": "", "Location access not allowed": "ئورۇن زىيارىتىغا ئىجازەت يوق", "Lost": "يوقاپ كەتتى", "Low": "", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Mojeek ئىزدەش API ئاچقۇچى", + "Month": "", "Monthly": "", "More": "تېخىمۇ كۆپ", "More Concise": "", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "", "New Chat": "يېڭى سۆھبەت", + "New Event": "", "New File": "", "New Folder": "يېڭى قىسقۇچ", "New Function": "يېڭى فۇنكسىيە", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "تېما بوش بولسا بولمايدۇ.", "Title Generation": "تېما ھاسىل قىلىش", "Title Generation Prompt": "تېما ھاسىل قىلىش تۈرتكەسى", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "چۈشۈرۈشكە بولىدىغان مودېل ئاتىنى كۆرۈش ئۈچۈن،", "To access the GGUF models available for downloading,": "چۈشۈرۈشكە بولىدىغان GGUF مودېللارنى كۆرۈش ئۈچۈن،", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI \"{{url}}\" غا تەلەپ يوللايدۇ", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI \"{{url}}/api/chat\" غا تەلەپ يوللايدۇ", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI \"{{url}}/chat/completions\" غا تەلەپ يوللايدۇ", + "Week": "", "Weekly": "", "What are you trying to achieve?": "نېمىگە ئېرىشمىكچىسىز؟", "What are you working on?": "نېمە ئىش قىلىۋاتىسىز؟", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "يېڭىلىق", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "قوزغىتىلسا، مودېل ھەر بىر سۆھبەت ئۇچۇرىغا ۋاقىتدا ئىنكاس قايتۇرىدۇ. بۇ ھالىتى تۇرۇشلۇق سۆھبەت ئۈچۈن پايدىلىق، بىراق ئاستا ئۈسكۈنىدە ئۈنۈمگە تەسىر قىلىدۇ.", "wherever you are": "قايسى يەردە بولسىڭىزمۇ", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "چىقىرىشنى بەتلەندۈرۈش ئۈچۈن ئىشلىتىلدۇ. ھەربىر بەت گىزىكچىلەر بىلەن ئايرىلىدۇ. كۆڭۈلدىكىچە چەكلەنگەن.", diff --git a/src/lib/i18n/locales/uk-UA/translation.json b/src/lib/i18n/locales/uk-UA/translation.json index 071d973601..5dde246b1f 100644 --- a/src/lib/i18n/locales/uk-UA/translation.json +++ b/src/lib/i18n/locales/uk-UA/translation.json @@ -75,9 +75,11 @@ "Add content here": "Додайте вміст сюди", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Додати файли", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Додати пам'ять", @@ -113,6 +115,7 @@ "AI": "", "All": "Усі", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Усі моделі видалені успішно", @@ -275,6 +278,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "Календар", + "Calendars": "", "Call": "Виклик", "Call feature is not supported when using Web STT engine": "Функція виклику не підтримується при використанні Web STT (розпізнавання мовлення) рушія", "Camera": "Камера", @@ -525,6 +529,7 @@ "Delete automation?": "", "Delete Chat": "Видалити чат", "Delete chat?": "Видалити чат?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Видалити папку?", "Delete function?": "Видалити функцію?", @@ -831,6 +836,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Оцінювання", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API ключ", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Приклад: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Приклад: УСІ", @@ -1200,6 +1209,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Слухаю...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1210,6 +1220,7 @@ "local": "", "Local": "Локальний", "Local Task Model": "", + "Location": "", "Location access not allowed": "Доступ до місцезнаходження не дозволено", "Lost": "Втрачене", "Low": "", @@ -1319,6 +1330,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "API ключ для пошуку Mojeek", + "Month": "", "Monthly": "", "More": "Більше", "More Concise": "", @@ -1337,6 +1349,7 @@ "New Automation": "", "New Button": "", "New Chat": "Новий чат", + "New Event": "", "New File": "", "New Folder": "Нова папка", "New Function": "", @@ -2017,6 +2030,7 @@ "Title cannot be an empty string.": "Заголовок не може бути порожнім рядком.", "Title Generation": "Генерація заголовка", "Title Generation Prompt": "Промт для генерування заголовків", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Щоб отримати доступ до назв доступних для завантаження моделей,", "To access the GGUF models available for downloading,": "Щоб отримати доступ до моделей GGUF, які можна завантажити,,", @@ -2187,6 +2201,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI надсилатиме запити до \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI надсилатиме запити до \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Чого ви прагнете досягти?", "What are you working on?": "Над чим ти працюєш?", @@ -2194,6 +2209,7 @@ "What is shared:": "", "What's New in": "Що нового в", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Коли активовано, модель буде відповідати на кожне повідомлення чату в режимі реального часу, генеруючи відповідь, як тільки користувач надішле повідомлення. Цей режим корисний для застосувань життєвих вітань чатів, але може позначитися на продуктивності на повільнішому апаратному забезпеченні.", "wherever you are": "де б ви не були", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/ur-PK/translation.json b/src/lib/i18n/locales/ur-PK/translation.json index 4d3049e375..bc6d4912e0 100644 --- a/src/lib/i18n/locales/ur-PK/translation.json +++ b/src/lib/i18n/locales/ur-PK/translation.json @@ -73,9 +73,11 @@ "Add content here": "یہاں مواد شامل کریں", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "فائلیں شامل کریں", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "میموری شامل کریں", @@ -111,6 +113,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -273,6 +276,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendars": "", "Call": "کال کریں", "Call feature is not supported when using Web STT engine": "کال کی خصوصیت ویب STT انجن استعمال کرتے وقت معاونت یافتہ نہیں ہے", "Camera": "کیمرہ", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "چیٹ حذف کریں", "Delete chat?": "چیٹ حذف کریں؟", + "Delete Event": "", "Delete File": "", "Delete folder?": "کیا فولڈر حذف کریں؟", "Delete function?": "حذف کریں؟", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "تشخیصات", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "سن رہے ہیں...", "Live": "", "Llama.cpp": "", @@ -1208,6 +1218,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "گم شدہ", "Low": "", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "مزید", "More Concise": "", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "", "New Chat": "نئی بات چیت", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "عنوان خالی اسٹرنگ نہیں ہو سکتا", "Title Generation": "", "Title Generation Prompt": "سرخی بنانے کی ہدایت", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "ڈاؤن لوڈ کرنے کے لئے دستیاب ماڈل کے ناموں تک رسائی حاصل کرنے کے لئے،", "To access the GGUF models available for downloading,": "GGUF ماڈلز تک رسائی حاصل کرنے کے لئے جو ڈاؤنلوڈنگ کے لئے دستیاب ہیں،", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "میں نیا کیا ہے", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json b/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json index d0b7f172c7..b4193be7b8 100644 --- a/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json +++ b/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json @@ -73,9 +73,11 @@ "Add content here": "Бу ерга таркиб қўшинг", "Add Custom Parameter": "Махсус параметр қўшинг", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Файлларни қўшиш", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Хотира қўшиш", @@ -111,6 +113,7 @@ "AI": "", "All": "Ҳаммаси", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Барча моделлар муваффақиятли ўчирилди", @@ -273,6 +276,7 @@ "Bypass Web Loader": "Веб юклагични четлаб ўтиш", "Cache Base Model List": "", "Calendar": "Календар", + "Calendars": "", "Call": "Қўнғироқ қилинг", "Call feature is not supported when using Web STT engine": "Wеб СТТ механизмидан фойдаланилганда қўнғироқ функсияси қўллаб-қувватланмайди", "Camera": "Камера", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "Чатни ўчириш", "Delete chat?": "Чат ўчирилсинми?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Жилд ўчирилсинми?", "Delete function?": "Функция ўчирилсинми?", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Баҳолар", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa АПИ калити", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Мисол: (&(обжеcтCласс=инетОргПерсон)(уид=%с))", "Example: ALL": "Мисол: АЛЛ", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Тингланмоқда...", "Live": "", "Llama.cpp": "Ллама.cпп", @@ -1208,6 +1218,7 @@ "local": "", "Local": "Маҳаллий", "Local Task Model": "Маҳаллий вазифа модели", + "Location": "", "Location access not allowed": "Жойлашувга рухсат берилмаган", "Lost": "Йўқотилган", "Low": "", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Можеэк қидирув АПИ калити", + "Month": "", "Monthly": "", "More": "Кўпроқ", "More Concise": "", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "", "New Chat": "Янги чат", + "New Event": "", "New File": "", "New Folder": "Янги жилд", "New Function": "Янги функсия", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "Сарлавҳа бўш қатор бўлиши мумкин эмас.", "Title Generation": "Сарлавҳа яратиш", "Title Generation Prompt": "Сарлавҳа яратиш таклифи", + "Title is required": "", "TLS": "ТЛС", "To access the available model names for downloading,": "Юклаб олиш учун мавжуд модел номларига кириш учун,", "To access the GGUF models available for downloading,": "Юклаб олиш мумкин бўлган ГГУФ моделларига кириш учун,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI “{{url}}” манзилига сўров юборади", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI “{{url}}/api/chat” манзилига сўров юборади", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI \"{{url}}/chat/completions\" манзилига сўров юборади", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Нимага эришмоқчисиз?", "What are you working on?": "Нима устида ишлаяпсиз?", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Ёқилганда, модел реал вақт режимида ҳар бир чат хабарига жавоб беради ва фойдаланувчи хабар юбориши биланоқ жавоб ҳосил қилади. Ушбу режим жонли чат иловалари учун фойдалидир, лекин секинроқ ускунанинг ишлашига таъсир қилиши мумкин.", "wherever you are": "қаерда бўлсангиз ҳам", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Чиқишни саҳифалаш керакми. Ҳар бир саҳифа горизонтал қоида ва саҳифа рақами билан ажратилади. Бирламчи параметрлар Фалсе.", diff --git a/src/lib/i18n/locales/uz-Latn-Uz/translation.json b/src/lib/i18n/locales/uz-Latn-Uz/translation.json index 9ac1af7080..b7c12ae135 100644 --- a/src/lib/i18n/locales/uz-Latn-Uz/translation.json +++ b/src/lib/i18n/locales/uz-Latn-Uz/translation.json @@ -73,9 +73,11 @@ "Add content here": "Bu yerga tarkib qo'shing", "Add Custom Parameter": "Maxsus parametr qo'shing", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Fayllarni qo'shish", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Xotira qo'shish", @@ -111,6 +113,7 @@ "AI": "", "All": "Hammasi", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Barcha modellar muvaffaqiyatli o'chirildi", @@ -273,6 +276,7 @@ "Bypass Web Loader": "Veb yuklagichni chetlab o'tish", "Cache Base Model List": "", "Calendar": "Kalendar", + "Calendars": "", "Call": "Qo'ng'iroq qiling", "Call feature is not supported when using Web STT engine": "Web STT mexanizmidan foydalanilganda qo'ng'iroq funksiyasi qo'llab-quvvatlanmaydi", "Camera": "Kamera", @@ -523,6 +527,7 @@ "Delete automation?": "", "Delete Chat": "Chatni oʻchirish", "Delete chat?": "Chat oʻchirilsinmi?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Jild oʻchirilsinmi?", "Delete function?": "Funktsiya o'chirilsinmi?", @@ -829,6 +834,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Baholar", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API kaliti", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Misol: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Misol: ALL", @@ -1198,6 +1207,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Tinglanmoqda...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1208,6 +1218,7 @@ "local": "", "Local": "Mahalliy", "Local Task Model": "Mahalliy vazifa modeli", + "Location": "", "Location access not allowed": "Joylashuvga ruxsat berilmagan", "Lost": "Yo'qotilgan", "Low": "", @@ -1317,6 +1328,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Mojeek qidiruv API kaliti", + "Month": "", "Monthly": "", "More": "Ko'proq", "More Concise": "", @@ -1335,6 +1347,7 @@ "New Automation": "", "New Button": "", "New Chat": "Yangi chat", + "New Event": "", "New File": "", "New Folder": "Yangi jild", "New Function": "Yangi funksiya", @@ -2013,6 +2026,7 @@ "Title cannot be an empty string.": "Sarlavha bo'sh qator bo'lishi mumkin emas.", "Title Generation": "Sarlavha yaratish", "Title Generation Prompt": "Sarlavha yaratish taklifi", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Yuklab olish uchun mavjud model nomlariga kirish uchun,", "To access the GGUF models available for downloading,": "Yuklab olish mumkin bo'lgan GGUF modellariga kirish uchun,", @@ -2183,6 +2197,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI “{{url}}” manziliga so‘rov yuboradi", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI “{{url}}/api/chat” manziliga so‘rov yuboradi", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI \"{{url}}/chat/completions\" manziliga so'rov yuboradi", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Nimaga erishmoqchisiz?", "What are you working on?": "Nima ustida ishlayapsiz?", @@ -2190,6 +2205,7 @@ "What is shared:": "", "What's New in": "", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Yoqilganda, model real vaqt rejimida har bir chat xabariga javob beradi va foydalanuvchi xabar yuborishi bilanoq javob hosil qiladi. Ushbu rejim jonli chat ilovalari uchun foydalidir, lekin sekinroq uskunaning ishlashiga ta'sir qilishi mumkin.", "wherever you are": "qayerda bo'lsangiz ham", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Chiqishni sahifalash kerakmi. Har bir sahifa gorizontal qoida va sahifa raqami bilan ajratiladi. Birlamchi parametrlar False.", diff --git a/src/lib/i18n/locales/vi-VN/translation.json b/src/lib/i18n/locales/vi-VN/translation.json index 170531b23e..9296b8b57c 100644 --- a/src/lib/i18n/locales/vi-VN/translation.json +++ b/src/lib/i18n/locales/vi-VN/translation.json @@ -72,9 +72,11 @@ "Add content here": "Thêm nội dung tại đây", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Thêm tệp", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Thêm bộ nhớ", @@ -110,6 +112,7 @@ "AI": "", "All": "Tất cả", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Tất cả các mô hình đã được xóa thành công", @@ -272,6 +275,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "Lịch", + "Calendars": "", "Call": "Gọi", "Call feature is not supported when using Web STT engine": "Tính năng gọi điện không được hỗ trợ khi sử dụng công cụ Web STT", "Camera": "Máy ảnh", @@ -522,6 +526,7 @@ "Delete automation?": "", "Delete Chat": "Xóa chat", "Delete chat?": "Xóa chat?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Xóa thư mục?", "Delete function?": "Xóa function?", @@ -828,6 +833,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Đánh giá", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Khóa API Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Ví dụ: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Ví dụ: TẤT CẢ", @@ -1197,6 +1206,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Đang nghe...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1207,6 +1217,7 @@ "local": "", "Local": "Cục bộ", "Local Task Model": "", + "Location": "", "Location access not allowed": "Không cho phép truy cập vị trí", "Lost": "Thua", "Low": "", @@ -1316,6 +1327,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Khóa API Mojeek Search", + "Month": "", "Monthly": "", "More": "Thêm", "More Concise": "", @@ -1334,6 +1346,7 @@ "New Automation": "", "New Button": "", "New Chat": "Tạo chat mới", + "New Event": "", "New File": "", "New Folder": "Thư mục Mới", "New Function": "", @@ -2011,6 +2024,7 @@ "Title cannot be an empty string.": "Tiêu đề không được phép bỏ trống", "Title Generation": "Tạo Tiêu đề", "Title Generation Prompt": "Prompt tạo tiêu đề", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Để truy cập tên các mô hình có sẵn để tải xuống,", "To access the GGUF models available for downloading,": "Để truy cập các mô hình GGUF có sẵn để tải xuống,", @@ -2181,6 +2195,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI sẽ thực hiện yêu cầu đến \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI sẽ thực hiện yêu cầu đến \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI sẽ thực hiện yêu cầu đến \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Bạn đang cố gắng đạt được điều gì?", "What are you working on?": "Bạn đang làm gì vậy?", @@ -2188,6 +2203,7 @@ "What is shared:": "", "What's New in": "Thông tin mới về", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Khi được bật, mô hình sẽ phản hồi từng tin nhắn trò chuyện trong thời gian thực, tạo ra phản hồi ngay khi người dùng gửi tin nhắn. Chế độ này hữu ích cho các ứng dụng trò chuyện trực tiếp, nhưng có thể ảnh hưởng đến hiệu suất trên phần cứng chậm hơn.", "wherever you are": "bất cứ nơi nào bạn đang ở", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/zh-CN/translation.json b/src/lib/i18n/locales/zh-CN/translation.json index 6c393de3dd..c8e04258c2 100644 --- a/src/lib/i18n/locales/zh-CN/translation.json +++ b/src/lib/i18n/locales/zh-CN/translation.json @@ -72,9 +72,11 @@ "Add content here": "在此添加内容", "Add Custom Parameter": "增加自定义参数", "Add Custom Prompt": "增加自定义提示词", + "Add description": "", "Add Details": "丰富细节", "Add Files": "添加文件", "Add Image": "添加图片", + "Add location": "", "Add Member": "添加成员", "Add Members": "添加成员", "Add Memory": "添加记忆", @@ -110,6 +112,7 @@ "AI": "AI", "All": "全部", "All chats have been unarchived.": "已成功取消全部对话的归档状态。", + "All day": "", "All models are now hidden": "已隐藏全部模型", "All models are now visible": "已显示全部模型", "All models deleted successfully": "已成功删除全部模型", @@ -272,6 +275,7 @@ "Bypass Web Loader": "绕过网页加载器", "Cache Base Model List": "缓存基础模型列表", "Calendar": "日历", + "Calendars": "", "Call": "语音通话", "Call feature is not supported when using Web STT engine": "使用 Web 语音转文字引擎时不支持语音通话功能", "Camera": "摄像头", @@ -522,6 +526,7 @@ "Delete automation?": "要删除此自动化吗?", "Delete Chat": "删除对话记录", "Delete chat?": "要删除此对话记录吗?", + "Delete Event": "", "Delete File": "删除文件", "Delete folder?": "要删除此分组吗?", "Delete function?": "要删除此函数吗?", @@ -828,6 +833,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "错误:ID 为“{{modelId}}”的模型已存在。请选择不同的模型 ID。", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "错误:模型 ID 不能为空。请输入有效的模型 ID。", "Evaluations": "模型评价", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa 接口密钥", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "例如:(&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "例如:ALL", @@ -1197,6 +1206,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "搜索并发数限制。默认为 0(无限制),设置为 1 则以顺序执行(推荐用于具有严格速率限制的接口,如 Brave 免费套餐)。", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "限制同时进行的嵌入请求数量,设为 0 表示不限制。", "List": "列表", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "正在倾听...", "Live": "实时", "Llama.cpp": "Llama.cpp", @@ -1207,6 +1217,7 @@ "local": "本地", "Local": "本地", "Local Task Model": "本地任务模型", + "Location": "", "Location access not allowed": "不允许访问位置信息", "Lost": "较差", "Low": "低", @@ -1316,6 +1327,7 @@ "Models Sharing": "分享模型", "Mojeek": "Mojeek", "Mojeek Search API Key": "Mojeek Search 接口密钥", + "Month": "", "Monthly": "每月", "More": "更多", "More Concise": "精炼表达", @@ -1334,6 +1346,7 @@ "New Automation": "创建自动化任务", "New Button": "新按钮", "New Chat": "新对话", + "New Event": "", "New File": "新建文件", "New Folder": "创建分组", "New Function": "新函数", @@ -2011,6 +2024,7 @@ "Title cannot be an empty string.": "标题不能为空", "Title Generation": "标题生成", "Title Generation Prompt": "用于自动生成标题的提示词", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "访问可下载的模型名称,", "To access the GGUF models available for downloading,": "访问可下载的 GGUF 模型,", @@ -2181,6 +2195,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI 将向 \"{{url}}\" 发出请求", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI 将向 \"{{url}}/api/chat\" 发出请求", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI 将向 \"{{url}}/chat/completions\" 发出请求", + "Week": "", "Weekly": "每周", "What are you trying to achieve?": "您想要达到什么目标?", "What are you working on?": "您在忙于什么?", @@ -2188,6 +2203,7 @@ "What is shared:": "共享的内容:", "What's New in": "最近更新内容于", "What's on your mind?": "聊聊您的想法吧!", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "启用后,模型将实时回答每条对话信息,在用户发送信息后立即生成回答。这种模式适用于即时对话应用,但在性能较低的设备上可能会影响响应速度", "wherever you are": "纵使身在远方,亦与世界同频", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "是否对输出内容进行分页。每页之间将用水平分隔线和页码隔开。默认为关闭", diff --git a/src/lib/i18n/locales/zh-TW/translation.json b/src/lib/i18n/locales/zh-TW/translation.json index 6ecaf0e655..f98a2bdb76 100644 --- a/src/lib/i18n/locales/zh-TW/translation.json +++ b/src/lib/i18n/locales/zh-TW/translation.json @@ -72,9 +72,11 @@ "Add content here": "在此新增內容", "Add Custom Parameter": "新增自訂參數", "Add Custom Prompt": "新增自訂提示詞", + "Add description": "", "Add Details": "豐富細節", "Add Files": "新增檔案", "Add Image": "新增圖片", + "Add location": "", "Add Member": "新增成員", "Add Members": "新增成員", "Add Memory": "新增記憶", @@ -110,6 +112,7 @@ "AI": "AI", "All": "全部", "All chats have been unarchived.": "已成功將所有對話解除封存。", + "All day": "", "All models are now hidden": "已隱藏全部模型", "All models are now visible": "已顯示全部模型", "All models deleted successfully": "成功刪除所有模型", @@ -272,6 +275,7 @@ "Bypass Web Loader": "繞過網頁載入器", "Cache Base Model List": "快取基礎模型清單", "Calendar": "日曆", + "Calendars": "", "Call": "通話", "Call feature is not supported when using Web STT engine": "使用網頁語音辨識 (Web STT) 引擎時不支援通話功能", "Camera": "相機", @@ -522,6 +526,7 @@ "Delete automation?": "要刪除此自動化嗎?", "Delete Chat": "刪除對話紀錄", "Delete chat?": "刪除對話紀錄?", + "Delete Event": "", "Delete File": "刪除檔案", "Delete folder?": "刪除資料夾?", "Delete function?": "刪除函式?", @@ -828,6 +833,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "錯誤:ID 為「{{modelId}}」的模型已存在。請選擇不同的模型 ID。", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "錯誤:模型 ID 不能為空。請輸入有效的模型 ID。", "Evaluations": "評估", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API 金鑰", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "範例:(&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "範例:ALL", @@ -1197,6 +1206,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "平行搜尋數量限制。預設為 0(無限制),設定為 1 則以順序執行(建議用於具有嚴格速率限制的服務,如 Brave 免費方案)。", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "限制同時進行的嵌入請求數量,設為 0 表示不限制。", "List": "列表", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "正在聆聽...", "Live": "即時", "Llama.cpp": "Llama.cpp", @@ -1207,6 +1217,7 @@ "local": "本機", "Local": "本機", "Local Task Model": "本機任務模型", + "Location": "", "Location access not allowed": "位置存取未獲允許", "Lost": "落敗", "Low": "低", @@ -1316,6 +1327,7 @@ "Models Sharing": "分享模型", "Mojeek": "Mojeek", "Mojeek Search API Key": "Mojeek 搜尋 API 金鑰", + "Month": "", "Monthly": "每月", "More": "更多", "More Concise": "精煉表達", @@ -1334,6 +1346,7 @@ "New Automation": "新增自動化", "New Button": "新按鈕", "New Chat": "新增對話", + "New Event": "", "New File": "新增檔案", "New Folder": "新增資料夾", "New Function": "新增函式", @@ -2011,6 +2024,7 @@ "Title cannot be an empty string.": "標題不能是空字串。", "Title Generation": "產生標題", "Title Generation Prompt": "產生標題的提示詞", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "若要存取可供下載的模型名稱,", "To access the GGUF models available for downloading,": "若要存取可供下載的 GGUF 模型,", @@ -2181,6 +2195,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI 將向 \"{{url}}\" 傳送請求", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI 將向 \"{{url}}/api/chat\" 傳送請求", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI 將向 \"{{url}}/chat/completions\" 傳送請求", + "Week": "", "Weekly": "每週", "What are you trying to achieve?": "您正在試圖完成什麼?", "What are you working on?": "您現在的工作是什麼?", @@ -2188,6 +2203,7 @@ "What is shared:": "會分享的內容:", "What's New in": "新功能", "What's on your mind?": "聊聊您的想法?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "啟用時,模型將即時回應每個對話訊息,在使用者傳送訊息後立即產生回應。此模式適用於即時對話應用程式,但在較慢的硬體上可能會影響效能。", "wherever you are": "無論您在何處", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "是否啟用輸出分頁功能,每頁會以水平線與頁碼分隔。預設為 False。", diff --git a/src/lib/stores/index.ts b/src/lib/stores/index.ts index a59944f50c..db779a7b84 100644 --- a/src/lib/stores/index.ts +++ b/src/lib/stores/index.ts @@ -29,6 +29,7 @@ export const MODEL_DOWNLOAD_POOL = writable({}); export const mobile = writable(false); export const socket: Writable = writable(null); +export const socketConnected: Writable = writable(true); export const activeUserIds: Writable = writable(null); export const activeChatIds: Writable> = writable(new Set()); export const USAGE_POOL: Writable = writable(null); @@ -230,6 +231,7 @@ type Settings = { ctrlEnterToSend?: boolean; renderMarkdownInPreviews?: boolean; recentEmojis?: string[]; + pinnedMenuItems?: string[]; system?: string; seed?: number; diff --git a/src/lib/utils/audio.ts b/src/lib/utils/audio.ts index 6effbc4137..94da18af67 100644 --- a/src/lib/utils/audio.ts +++ b/src/lib/utils/audio.ts @@ -1,32 +1,39 @@ +type AudioQueueEvent = 'stop' | 'empty-queue' | 'id-change'; + +interface AudioQueueStopDetail { + event: AudioQueueEvent; + id: string | null; +} + +export type OnStoppedCallback = (detail: AudioQueueStopDetail) => void; + export class AudioQueue { - constructor(audioElement) { + private audio: HTMLAudioElement; + private queue: string[] = []; + private current: string | null = null; + private readonly _onEnded = () => this.next(); + + id: string | null = null; + onStopped: OnStoppedCallback | null = null; + + constructor(audioElement: HTMLAudioElement) { this.audio = audioElement; - this.queue = []; - this.current = null; - this.id = null; - - this._onEnded = () => this.next(); this.audio.addEventListener('ended', this._onEnded); - - this.onStopped = null; // optional callback } - setId(newId) { - console.log('Setting audio queue ID to:', newId); - if (this.id !== newId) { - this.stop(); - this.id = newId; - if (this.onStopped) this.onStopped({ event: 'id-change', id: newId }); - } + setId(newId: string) { + if (this.id === newId) return; + + this.#halt(); + this.id = newId; + this.onStopped?.({ event: 'id-change', id: newId }); } - setPlaybackRate(rate) { - console.log('Setting audio playback rate to:', rate); + setPlaybackRate(rate: number) { this.audio.playbackRate = rate; } - enqueue(url) { - console.log('Enqueuing audio URL:', url); + enqueue(url: string) { this.queue.push(url); // Auto-play if nothing is currently playing or loaded @@ -44,30 +51,37 @@ export class AudioQueue { } next() { - this.current = this.queue.shift(); + this.current = this.queue.shift() ?? null; + if (this.current) { this.audio.src = this.current; this.audio.play(); - console.log('Playing audio URL:', this.current); } else { - this.stop(); - if (this.onStopped) this.onStopped({ event: 'empty-queue', id: this.id }); + this.#halt(); + this.onStopped?.({ event: 'empty-queue', id: this.id }); } } stop() { + this.#halt(); + this.onStopped?.({ event: 'stop', id: this.id }); + } + + destroy() { + this.audio.removeEventListener('ended', this._onEnded); + this.#halt(); + this.onStopped = null; + } + + /** + * Pause audio and clear queue without firing onStopped. + * Callers that need the callback should invoke it themselves. + */ + #halt() { this.audio.pause(); this.audio.currentTime = 0; this.audio.src = ''; this.queue = []; this.current = null; - if (this.onStopped) this.onStopped({ event: 'stop', id: this.id }); - } - - destroy() { - this.audio.removeEventListener('ended', this._onEnded); - this.stop(); - this.onStopped = null; - this.audio = null; } } diff --git a/src/routes/(app)/automations/+page.svelte b/src/routes/(app)/automations/+page.svelte index e48dd3be37..406510e68f 100644 --- a/src/routes/(app)/automations/+page.svelte +++ b/src/routes/(app)/automations/+page.svelte @@ -165,7 +165,10 @@ }; onMount(async () => { - if ($user?.role !== 'admin' && !($user?.permissions?.features?.automations ?? false)) { + if ( + !$config?.features?.enable_automations || + ($user?.role !== 'admin' && !($user?.permissions?.features?.automations ?? false)) + ) { goto('/'); return; } diff --git a/src/routes/(app)/automations/[id]/+page.svelte b/src/routes/(app)/automations/[id]/+page.svelte index 51745fa01e..5e9f71b70c 100644 --- a/src/routes/(app)/automations/[id]/+page.svelte +++ b/src/routes/(app)/automations/[id]/+page.svelte @@ -4,7 +4,7 @@ import { onMount, getContext } from 'svelte'; import { page } from '$app/stores'; - import { user, showSidebar } from '$lib/stores'; + import { user, showSidebar, config } from '$lib/stores'; import { getAutomationById } from '$lib/apis/automations'; import AutomationEditor from '$lib/components/automations/AutomationEditor.svelte'; @@ -18,7 +18,10 @@ $: automationId = $page.params.id; onMount(async () => { - if ($user?.role !== 'admin' && !($user?.permissions?.features?.automations ?? false)) { + if ( + !$config?.features?.enable_automations || + ($user?.role !== 'admin' && !($user?.permissions?.features?.automations ?? false)) + ) { goto('/'); return; } diff --git a/src/routes/(app)/calendar/+page.svelte b/src/routes/(app)/calendar/+page.svelte new file mode 100644 index 0000000000..ec61a27eb9 --- /dev/null +++ b/src/routes/(app)/calendar/+page.svelte @@ -0,0 +1,378 @@ + + + + {$i18n.t('Calendar')} • {$WEBUI_NAME} + + + refresh()} + on:delete={() => refresh()} +/> + +
+ {#if loaded} + + + +
+ + + + +
+ +
+
+ {:else} +
+ +
+ {/if} +
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 8aeda16594..0dc8170eef 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -19,6 +19,7 @@ WEBUI_DEPLOYMENT_ID, mobile, socket, + socketConnected, chatId, chats, currentChatPage, @@ -51,7 +52,7 @@ import 'tippy.js/dist/tippy.css'; import { executeToolServer, getBackendConfig, getModels, getVersion } from '$lib/apis'; - import { getSessionUser, userSignOut } from '$lib/apis/auths'; + import { getSessionUser, updateUserTimezone, userSignOut } from '$lib/apis/auths'; import { getAllTags, getChatList } from '$lib/apis/chats'; import { chatCompletion } from '$lib/apis/openai'; import { @@ -62,7 +63,7 @@ } from '$lib/utils/connections'; import { WEBUI_API_BASE_URL, WEBUI_BASE_URL, WEBUI_HOSTNAME } from '$lib/constants'; - import { bestMatchingLanguage, displayFileHandler } from '$lib/utils'; + import { bestMatchingLanguage, displayFileHandler, getUserTimezone } from '$lib/utils'; import { setTextScale } from '$lib/utils/text-scale'; import NotificationToast from '$lib/components/NotificationToast.svelte'; @@ -127,8 +128,17 @@ console.log('connect_error', err); }); + let hasConnectedOnce = false; + _socket.on('connect', async () => { console.log('connected', _socket.id); + + if (hasConnectedOnce) { + socketConnected.set(true); + toast.success($i18n.t('Reconnected')); + } + hasConnectedOnce = true; + const res = await getVersion(localStorage.token); const deploymentId = res?.deployment_id ?? null; @@ -182,6 +192,8 @@ _socket.on('disconnect', (reason, details) => { console.log(`Socket ${_socket.id} disconnected due to ${reason}`); + socketConnected.set(false); + toast.warning($i18n.t('Connection lost. Reconnecting...')); if (heartbeatInterval) { clearInterval(heartbeatInterval); @@ -425,13 +437,13 @@ return; } - let isFocused = document.visibilityState !== 'visible'; + let isInBackground = document.visibilityState !== 'visible'; if (window.electronAPI) { const res = await window.electronAPI.send({ type: 'window:isFocused' }); if (res) { - isFocused = res.isFocused; + isInBackground = !res.isFocused; } } @@ -439,7 +451,39 @@ const type = event?.data?.type ?? null; const data = event?.data?.data ?? null; - if ((event.chat_id !== $chatId && !$temporaryChatEnabled) || isFocused) { + // Calendar alerts are not chat-scoped — handle before chat_id checks + if (type === 'calendar:alert' && data) { + const timeStr = + data.minutes_until <= 0 + ? $i18n.t('Starting now') + : data.minutes_until === 1 + ? $i18n.t('Starting in 1 minute') + : $i18n.t('Starting in {{count}} minutes', { count: data.minutes_until }); + + toast.custom(NotificationToast, { + componentProps: { + onClick: () => { + goto('/calendar'); + }, + title: data.title, + content: timeStr + }, + duration: 30000, + unstyled: true + }); + + if ($isLastActiveTab) { + if ($settings?.notificationEnabled ?? false) { + new Notification(`${data.title} • Open WebUI`, { + body: timeStr, + icon: `${WEBUI_BASE_URL}/static/favicon.png` + }); + } + } + return; + } + + if ((event.chat_id !== $chatId && !$temporaryChatEnabled) || isInBackground) { if (type === 'chat:completion') { const { done, content, title } = data; const displayTitle = title || $i18n.t('New Chat'); @@ -607,17 +651,17 @@ // check url path const channel = $page.url.pathname.includes(`/channels/${event.channel_id}`); - let isFocused = document.visibilityState !== 'visible'; + let isInBackground = document.visibilityState !== 'visible'; if (window.electronAPI) { const res = await window.electronAPI.send({ type: 'window:isFocused' }); if (res) { - isFocused = res.isFocused; + isInBackground = !res.isFocused; } } - if ((!channel || isFocused) && event?.user?.id !== $user?.id) { + if ((!channel || isInBackground) && event?.user?.id !== $user?.id) { await tick(); const type = event?.data?.type ?? null; const data = event?.data?.data ?? null; @@ -989,6 +1033,12 @@ console.error('Error refreshing backend config:', error); } + // Keep user timezone in sync on every app load/refresh + const timezone = getUserTimezone(); + if (timezone) { + updateUserTimezone(localStorage.token, timezone); + } + // Relay auth token to desktop app for API access if (window.electronAPI?.send) { window.electronAPI diff --git a/static/favicon.png b/static/favicon.png index 63735ad461..10c84f440c 100644 Binary files a/static/favicon.png and b/static/favicon.png differ diff --git a/static/static/favicon.ico b/static/static/favicon.ico index 14c5f9c6d4..b819d42f96 100644 Binary files a/static/static/favicon.ico and b/static/static/favicon.ico differ diff --git a/static/static/favicon.png b/static/static/favicon.png index 63735ad461..10c84f440c 100644 Binary files a/static/static/favicon.png and b/static/static/favicon.png differ