Skip to content

Commit 2b26355

Browse files
authored
Merge pull request open-webui#20560 from open-webui/dev
0.7.2
2 parents f2a360c + d81a363 commit 2b26355

73 files changed

Lines changed: 326 additions & 69 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.7.2] - 2026-01-10
9+
10+
### Fixed
11+
12+
- ⚡ Users no longer experience database connection timeouts under high concurrency due to connections being held during LLM calls, telemetry collection, and file status streaming. [#20545](https://github.com/open-webui/open-webui/pull/20545), [#20542](https://github.com/open-webui/open-webui/pull/20542), [#20547](https://github.com/open-webui/open-webui/pull/20547)
13+
- 📝 Users can now create and save prompts in the workspace prompts editor without encountering errors. [Commit](https://github.com/open-webui/open-webui/commit/ab99d3b1129cffbc13cf7de5aa897692e3f8662e)
14+
- 🎙️ Users can now use local Whisper for speech-to-text when STT_ENGINE is left empty (the default for local mode). [#20534](https://github.com/open-webui/open-webui/pull/20534)
15+
- 📊 The Evaluations page now loads faster by eliminating duplicate API calls to the leaderboard and feedbacks endpoints. [Commit](https://github.com/open-webui/open-webui/commit/2dd09223f2aac301a4d5c17fb667d974c34f3ff1)
16+
- 🌐 Fixed missing Settings tab i18n label keys. [#20526](https://github.com/open-webui/open-webui/pull/20526)
17+
818
## [0.7.1] - 2026-01-09
919

1020
### Fixed

backend/open_webui/routers/audio.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -334,8 +334,8 @@ def load_speech_pipeline(request):
334334
async def speech(request: Request, user=Depends(get_verified_user)):
335335
if request.app.state.config.TTS_ENGINE == "":
336336
raise HTTPException(
337-
status_code=status.HTTP_403_FORBIDDEN,
338-
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
337+
status_code=status.HTTP_404_NOT_FOUND,
338+
detail=ERROR_MESSAGES.NOT_FOUND,
339339
)
340340

341341
if user.role != "admin" and not has_permission(
@@ -1169,12 +1169,6 @@ def transcription(
11691169
language: Optional[str] = Form(None),
11701170
user=Depends(get_verified_user),
11711171
):
1172-
if request.app.state.config.STT_ENGINE == "":
1173-
raise HTTPException(
1174-
status_code=status.HTTP_403_FORBIDDEN,
1175-
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
1176-
)
1177-
11781172
if user.role != "admin" and not has_permission(
11791173
user.id, "chat.stt", request.app.state.config.USER_PERMISSIONS
11801174
):

backend/open_webui/routers/channels.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,15 +1256,17 @@ async def post_new_message(
12561256

12571257
active_user_ids = get_user_ids_from_room(f"channel:{channel.id}")
12581258

1259+
# NOTE: We intentionally do NOT pass db to background_handler.
1260+
# Background tasks should manage their own short-lived sessions to avoid
1261+
# holding database connections during slow operations (e.g., LLM calls).
12591262
async def background_handler():
1260-
await model_response_handler(request, channel, message, user, db)
1263+
await model_response_handler(request, channel, message, user)
12611264
await send_notification(
12621265
request.app.state.WEBUI_NAME,
12631266
request.app.state.config.WEBUI_URL,
12641267
channel,
12651268
message,
12661269
active_user_ids,
1267-
db=db,
12681270
)
12691271

12701272
background_tasks.add_task(background_handler)

backend/open_webui/routers/files.py

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -495,32 +495,35 @@ async def get_file_process_status(
495495
if stream:
496496
MAX_FILE_PROCESSING_DURATION = 3600 * 2
497497

498-
async def event_stream(file_item):
499-
if file_item:
500-
for _ in range(MAX_FILE_PROCESSING_DURATION):
501-
file_item = Files.get_file_by_id(file_item.id, db=db)
502-
if file_item:
503-
data = file_item.model_dump().get("data", {})
504-
status = data.get("status")
505-
506-
if status:
507-
event = {"status": status}
508-
if status == "failed":
509-
event["error"] = data.get("error")
510-
511-
yield f"data: {json.dumps(event)}\n\n"
512-
if status in ("completed", "failed"):
513-
break
514-
else:
515-
# Legacy
498+
async def event_stream(file_id):
499+
# NOTE: We intentionally do NOT capture the request's db session here.
500+
# Each poll creates its own short-lived session to avoid holding a
501+
# connection for hours. A WebSocket push would be more efficient.
502+
for _ in range(MAX_FILE_PROCESSING_DURATION):
503+
file_item = Files.get_file_by_id(file_id) # Creates own session
504+
if file_item:
505+
data = file_item.model_dump().get("data", {})
506+
status = data.get("status")
507+
508+
if status:
509+
event = {"status": status}
510+
if status == "failed":
511+
event["error"] = data.get("error")
512+
513+
yield f"data: {json.dumps(event)}\n\n"
514+
if status in ("completed", "failed"):
516515
break
516+
else:
517+
# Legacy
518+
break
519+
else:
520+
yield f"data: {json.dumps({'status': 'not_found'})}\n\n"
521+
break
517522

518-
await asyncio.sleep(0.5)
519-
else:
520-
yield f"data: {json.dumps({'status': 'not_found'})}\n\n"
523+
await asyncio.sleep(1)
521524

522525
return StreamingResponse(
523-
event_stream(file),
526+
event_stream(file.id),
524527
media_type="text/event-stream",
525528
)
526529
else:

backend/open_webui/utils/auth.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@
4444

4545
from fastapi import BackgroundTasks, Depends, HTTPException, Request, Response, status
4646
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
47-
from sqlalchemy.orm import Session
48-
from open_webui.internal.db import get_session
4947

5048

5149
log = logging.getLogger(__name__)
@@ -279,7 +277,10 @@ async def get_current_user(
279277
response: Response,
280278
background_tasks: BackgroundTasks,
281279
auth_token: HTTPAuthorizationCredentials = Depends(bearer_security),
282-
db: Session = Depends(get_session),
280+
# NOTE: We intentionally do NOT use Depends(get_session) here.
281+
# Sessions are managed internally with short-lived context managers.
282+
# This ensures connections are released immediately after auth queries,
283+
# not held for the entire request duration (e.g., during 30+ second LLM calls).
283284
):
284285
token = None
285286

@@ -294,7 +295,7 @@ async def get_current_user(
294295

295296
# auth by api key
296297
if token.startswith("sk-"):
297-
user = get_current_user_by_api_key(request, token, db=db)
298+
user = get_current_user_by_api_key(request, token)
298299

299300
# Add user info to current span
300301
current_span = trace.get_current_span()
@@ -323,7 +324,7 @@ async def get_current_user(
323324
detail="Invalid token",
324325
)
325326

326-
user = Users.get_user_by_id(data["id"], db=db)
327+
user = Users.get_user_by_id(data["id"])
327328
if user is None:
328329
raise HTTPException(
329330
status_code=status.HTTP_401_UNAUTHORIZED,
@@ -373,8 +374,9 @@ async def get_current_user(
373374
raise e
374375

375376

376-
def get_current_user_by_api_key(request, api_key: str, db: Session = None):
377-
user = Users.get_user_by_api_key(api_key, db=db)
377+
def get_current_user_by_api_key(request, api_key: str):
378+
# Each function call manages its own short-lived session internally
379+
user = Users.get_user_by_api_key(api_key)
378380

379381
if user is None:
380382
raise HTTPException(
@@ -402,7 +404,7 @@ def get_current_user_by_api_key(request, api_key: str, db: Session = None):
402404
current_span.set_attribute("client.user.role", user.role)
403405
current_span.set_attribute("client.auth.type", "api_key")
404406

405-
Users.update_last_active_by_id(user.id, db=db)
407+
Users.update_last_active_by_id(user.id)
406408
return user
407409

408410

backend/open_webui/utils/payload.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
)
77

88
from typing import Callable, Optional
9+
import copy
910
import json
1011

1112

@@ -286,6 +287,7 @@ def convert_payload_openai_to_ollama(openai_payload: dict) -> dict:
286287
Returns:
287288
dict: A modified payload compatible with the Ollama API.
288289
"""
290+
openai_payload = copy.deepcopy(openai_payload)
289291
ollama_payload = {}
290292

291293
# Mapping basic model and message details

backend/open_webui/utils/telemetry/metrics.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,12 @@ def observe_active_users(
141141
def observe_total_registered_users(
142142
options: metrics.CallbackOptions,
143143
) -> Sequence[metrics.Observation]:
144+
# IMPORTANT: Use get_num_users() for efficient COUNT(*) query.
145+
# Do NOT use len(get_users()["users"]) - it loads ALL user records into memory,
146+
# causing connection pool exhaustion on high-latency databases (e.g., Aurora).
144147
return [
145148
metrics.Observation(
146-
value=len(Users.get_users()["users"]),
149+
value=Users.get_num_users() or 0,
147150
)
148151
]
149152

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "open-webui",
3-
"version": "0.7.1",
3+
"version": "0.7.2",
44
"private": true,
55
"scripts": {
66
"dev": "npm run pyodide:fetch && vite dev --host",

src/lib/components/admin/Evaluations/Feedbacks.svelte

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,7 @@
8080
}
8181
};
8282
83-
$: if (page) {
84-
getFeedbacks();
85-
}
86-
87-
$: if (orderBy && direction) {
83+
$: if (orderBy && direction && page) {
8884
getFeedbacks();
8985
}
9086

0 commit comments

Comments
 (0)