Skip to content

Commit c52dfa5

Browse files
Merge remote-tracking branch 'upstream/dev' into dev
2 parents 3765a50 + 4a55167 commit c52dfa5

20 files changed

Lines changed: 2881 additions & 373 deletions

File tree

backend/open_webui/config.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3410,6 +3410,24 @@ class BannerModel(BaseModel):
34103410
os.environ.get("EXTERNAL_WEB_LOADER_API_KEY", ""),
34113411
)
34123412

3413+
YANDEX_WEB_SEARCH_URL = PersistentConfig(
3414+
"YANDEX_WEB_SEARCH_URL",
3415+
"rag.web.search.yandex_web_search_url",
3416+
os.environ.get("YANDEX_WEB_SEARCH_URL", ""),
3417+
)
3418+
3419+
YANDEX_WEB_SEARCH_API_KEY = PersistentConfig(
3420+
"YANDEX_WEB_SEARCH_API_KEY",
3421+
"rag.web.search.yandex_web_search_api_key",
3422+
os.environ.get("YANDEX_WEB_SEARCH_API_KEY", ""),
3423+
)
3424+
3425+
YANDEX_WEB_SEARCH_CONFIG = PersistentConfig(
3426+
"YANDEX_WEB_SEARCH_CONFIG",
3427+
"rag.web.search.yandex_web_search_config",
3428+
os.environ.get("YANDEX_WEB_SEARCH_CONFIG", ""),
3429+
)
3430+
34133431
####################################
34143432
# Images
34153433
####################################

backend/open_webui/main.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,9 @@
353353
EXTERNAL_WEB_SEARCH_API_KEY,
354354
EXTERNAL_WEB_LOADER_URL,
355355
EXTERNAL_WEB_LOADER_API_KEY,
356+
YANDEX_WEB_SEARCH_URL,
357+
YANDEX_WEB_SEARCH_API_KEY,
358+
YANDEX_WEB_SEARCH_CONFIG,
356359
# WebUI
357360
WEBUI_AUTH,
358361
WEBUI_NAME,
@@ -1008,6 +1011,9 @@ async def lifespan(app: FastAPI):
10081011
app.state.config.EXTERNAL_WEB_SEARCH_API_KEY = EXTERNAL_WEB_SEARCH_API_KEY
10091012
app.state.config.EXTERNAL_WEB_LOADER_URL = EXTERNAL_WEB_LOADER_URL
10101013
app.state.config.EXTERNAL_WEB_LOADER_API_KEY = EXTERNAL_WEB_LOADER_API_KEY
1014+
app.state.config.YANDEX_WEB_SEARCH_URL = YANDEX_WEB_SEARCH_URL
1015+
app.state.config.YANDEX_WEB_SEARCH_API_KEY = YANDEX_WEB_SEARCH_API_KEY
1016+
app.state.config.YANDEX_WEB_SEARCH_CONFIG = YANDEX_WEB_SEARCH_CONFIG
10111017

10121018

10131019
app.state.config.PLAYWRIGHT_WS_URL = PLAYWRIGHT_WS_URL
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
"""Add prompt history table
2+
3+
Revision ID: 374d2f66af06
4+
Revises: c440947495f3
5+
Create Date: 2026-01-23 17:15:00.000000
6+
7+
"""
8+
9+
from typing import Sequence, Union
10+
import uuid
11+
12+
from alembic import op
13+
import sqlalchemy as sa
14+
15+
16+
revision: str = "374d2f66af06"
17+
down_revision: Union[str, None] = "c440947495f3"
18+
branch_labels: Union[str, Sequence[str], None] = None
19+
depends_on: Union[str, Sequence[str], None] = None
20+
21+
22+
def upgrade() -> None:
23+
conn = op.get_bind()
24+
25+
# Step 1: Read existing data from OLD table (schema likely command as PK)
26+
# We use batch_alter previously, but we want to move to new table.
27+
# We need to assume the OLD structure.
28+
29+
old_prompt_table = sa.table(
30+
"prompt",
31+
sa.column("command", sa.Text()),
32+
sa.column("user_id", sa.Text()),
33+
sa.column("title", sa.Text()),
34+
sa.column("content", sa.Text()),
35+
sa.column("timestamp", sa.BigInteger()),
36+
sa.column("access_control", sa.JSON()),
37+
)
38+
39+
# Check if table exists/read data
40+
try:
41+
existing_prompts = conn.execute(
42+
sa.select(
43+
old_prompt_table.c.command,
44+
old_prompt_table.c.user_id,
45+
old_prompt_table.c.title,
46+
old_prompt_table.c.content,
47+
old_prompt_table.c.timestamp,
48+
old_prompt_table.c.access_control,
49+
)
50+
).fetchall()
51+
except Exception:
52+
# Fallback if table doesn't exist (new install)
53+
existing_prompts = []
54+
55+
# Step 2: Create new prompt table with 'id' as PRIMARY KEY
56+
op.create_table(
57+
"prompt_new",
58+
sa.Column("id", sa.Text(), primary_key=True),
59+
sa.Column("command", sa.String(), unique=True, index=True),
60+
sa.Column("user_id", sa.String(), nullable=False),
61+
sa.Column("name", sa.Text(), nullable=False),
62+
sa.Column("content", sa.Text(), nullable=False),
63+
sa.Column("data", sa.JSON(), nullable=True),
64+
sa.Column("meta", sa.JSON(), nullable=True),
65+
sa.Column("access_control", sa.JSON(), nullable=True),
66+
sa.Column("is_active", sa.Boolean(), nullable=False, server_default="1"),
67+
sa.Column("version_id", sa.Text(), nullable=True),
68+
sa.Column("tags", sa.JSON(), nullable=True),
69+
sa.Column("created_at", sa.BigInteger(), nullable=False),
70+
sa.Column("updated_at", sa.BigInteger(), nullable=False),
71+
)
72+
73+
# Step 3: Create prompt_history table
74+
op.create_table(
75+
"prompt_history",
76+
sa.Column("id", sa.Text(), primary_key=True),
77+
sa.Column("prompt_id", sa.Text(), nullable=False, index=True),
78+
sa.Column("parent_id", sa.Text(), nullable=True),
79+
sa.Column("snapshot", sa.JSON(), nullable=False),
80+
sa.Column("user_id", sa.Text(), nullable=False),
81+
sa.Column("commit_message", sa.Text(), nullable=True),
82+
sa.Column("created_at", sa.BigInteger(), nullable=False),
83+
)
84+
85+
# Step 4: Migrate data
86+
prompt_new_table = sa.table(
87+
"prompt_new",
88+
sa.column("id", sa.Text()),
89+
sa.column("command", sa.String()),
90+
sa.column("user_id", sa.String()),
91+
sa.column("name", sa.Text()),
92+
sa.column("content", sa.Text()),
93+
sa.column("data", sa.JSON()),
94+
sa.column("meta", sa.JSON()),
95+
sa.column("access_control", sa.JSON()),
96+
sa.column("is_active", sa.Boolean()),
97+
sa.column("version_id", sa.Text()),
98+
sa.column("tags", sa.JSON()),
99+
sa.column("created_at", sa.BigInteger()),
100+
sa.column("updated_at", sa.BigInteger()),
101+
)
102+
103+
prompt_history_table = sa.table(
104+
"prompt_history",
105+
sa.column("id", sa.Text()),
106+
sa.column("prompt_id", sa.Text()),
107+
sa.column("parent_id", sa.Text()),
108+
sa.column("snapshot", sa.JSON()),
109+
sa.column("user_id", sa.Text()),
110+
sa.column("commit_message", sa.Text()),
111+
sa.column("created_at", sa.BigInteger()),
112+
)
113+
114+
for row in existing_prompts:
115+
command = row[0]
116+
user_id = row[1]
117+
title = row[2]
118+
content = row[3]
119+
timestamp = row[4]
120+
access_control = row[5]
121+
122+
new_uuid = str(uuid.uuid4())
123+
history_uuid = str(uuid.uuid4())
124+
clean_command = command[1:] if command and command.startswith("/") else command
125+
126+
# Insert into prompt_new
127+
conn.execute(
128+
sa.insert(prompt_new_table).values(
129+
id=new_uuid,
130+
command=clean_command,
131+
user_id=user_id,
132+
name=title,
133+
content=content,
134+
data={},
135+
meta={},
136+
access_control=access_control,
137+
is_active=True,
138+
version_id=history_uuid,
139+
tags=[],
140+
created_at=timestamp,
141+
updated_at=timestamp,
142+
)
143+
)
144+
145+
# Create initial history entry
146+
conn.execute(
147+
sa.insert(prompt_history_table).values(
148+
id=history_uuid,
149+
prompt_id=new_uuid,
150+
parent_id=None,
151+
snapshot={
152+
"name": title,
153+
"content": content,
154+
"command": clean_command,
155+
"data": {},
156+
"meta": {},
157+
"access_control": access_control,
158+
},
159+
user_id=user_id,
160+
commit_message=None,
161+
created_at=timestamp,
162+
)
163+
)
164+
165+
# Step 5: Replace old table with new one
166+
op.drop_table("prompt")
167+
op.rename_table("prompt_new", "prompt")
168+
169+
170+
def downgrade() -> None:
171+
conn = op.get_bind()
172+
173+
# Step 1: Read new data
174+
prompt_table = sa.table(
175+
"prompt",
176+
sa.column("command", sa.String()),
177+
sa.column("name", sa.Text()),
178+
sa.column("created_at", sa.BigInteger()),
179+
sa.column("user_id", sa.Text()),
180+
sa.column("content", sa.Text()),
181+
sa.column("access_control", sa.JSON()),
182+
)
183+
184+
try:
185+
current_data = conn.execute(
186+
sa.select(
187+
prompt_table.c.command,
188+
prompt_table.c.name,
189+
prompt_table.c.created_at,
190+
prompt_table.c.user_id,
191+
prompt_table.c.content,
192+
prompt_table.c.access_control,
193+
)
194+
).fetchall()
195+
except Exception:
196+
current_data = []
197+
198+
# Step 2: Drop history and table
199+
op.drop_table("prompt_history")
200+
op.drop_table("prompt")
201+
202+
# Step 3: Recreate old table (command as PK?)
203+
# Assuming old schema:
204+
op.create_table(
205+
"prompt",
206+
sa.Column("command", sa.String(), primary_key=True),
207+
sa.Column("user_id", sa.String()),
208+
sa.Column("title", sa.Text()),
209+
sa.Column("content", sa.Text()),
210+
sa.Column("timestamp", sa.BigInteger()),
211+
sa.Column("access_control", sa.JSON()),
212+
sa.Column("id", sa.Integer(), nullable=True),
213+
)
214+
215+
# Step 4: Restore data
216+
old_prompt_table = sa.table(
217+
"prompt",
218+
sa.column("command", sa.String()),
219+
sa.column("user_id", sa.String()),
220+
sa.column("title", sa.Text()),
221+
sa.column("content", sa.Text()),
222+
sa.column("timestamp", sa.BigInteger()),
223+
sa.column("access_control", sa.JSON()),
224+
)
225+
226+
for row in current_data:
227+
command = row[0]
228+
name = row[1]
229+
created_at = row[2]
230+
user_id = row[3]
231+
content = row[4]
232+
access_control = row[5]
233+
234+
# Restore leading /
235+
old_command = (
236+
"/" + command if command and not command.startswith("/") else command
237+
)
238+
239+
conn.execute(
240+
sa.insert(old_prompt_table).values(
241+
command=old_command,
242+
user_id=user_id,
243+
title=name,
244+
content=content,
245+
timestamp=created_at,
246+
access_control=access_control,
247+
)
248+
)

0 commit comments

Comments
 (0)