refac
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
import json
|
||||
import logging
|
||||
|
||||
import aiohttp
|
||||
@@ -9,6 +8,7 @@ from open_webui.env import (
|
||||
)
|
||||
from open_webui.models.users import UserModel
|
||||
from open_webui.utils.headers import include_user_info_headers
|
||||
from open_webui.utils.json_codec import JSONCodec
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -235,7 +235,7 @@ def convert_anthropic_to_openai_payload(
|
||||
'function': {
|
||||
'name': block.get('name', ''),
|
||||
'arguments': (
|
||||
json.dumps(block.get('input', {}))
|
||||
JSONCodec.dumps(block.get('input', {}))
|
||||
if isinstance(block.get('input'), dict)
|
||||
else str(block.get('input', '{}'))
|
||||
),
|
||||
@@ -531,8 +531,8 @@ def convert_openai_to_anthropic_response(
|
||||
for tool_call in tool_calls:
|
||||
function = tool_call.get('function', {})
|
||||
try:
|
||||
tool_input = json.loads(function.get('arguments', '{}'))
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
tool_input = JSONCodec.loads(function.get('arguments', '{}'))
|
||||
except (JSONCodec.JSONDecodeError, TypeError):
|
||||
tool_input = {}
|
||||
content.append(
|
||||
{
|
||||
@@ -643,7 +643,7 @@ async def openai_stream_to_anthropic_stream(openai_stream_generator, model: str
|
||||
'usage': {'input_tokens': input_tokens or 0, 'output_tokens': 0},
|
||||
},
|
||||
}
|
||||
yield f'event: message_start\ndata: {json.dumps(message_start)}\n\n'.encode()
|
||||
yield f'event: message_start\ndata: {JSONCodec.dumps(message_start)}\n\n'.encode()
|
||||
|
||||
try:
|
||||
async for chunk in openai_stream_generator:
|
||||
@@ -663,8 +663,8 @@ async def openai_stream_to_anthropic_stream(openai_stream_generator, model: str
|
||||
continue
|
||||
|
||||
try:
|
||||
data = json.loads(data_string)
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
data = JSONCodec.loads(data_string)
|
||||
except (JSONCodec.JSONDecodeError, TypeError):
|
||||
continue
|
||||
|
||||
usage_data = data.get('usage')
|
||||
@@ -730,7 +730,7 @@ async def openai_stream_to_anthropic_stream(openai_stream_generator, model: str
|
||||
'index': current_block_index,
|
||||
'content_block': {'type': 'thinking', 'thinking': ''},
|
||||
}
|
||||
yield f'event: content_block_start\ndata: {json.dumps(block_start)}\n\n'.encode()
|
||||
yield f'event: content_block_start\ndata: {JSONCodec.dumps(block_start)}\n\n'.encode()
|
||||
thinking_block_open = True
|
||||
|
||||
block_delta = {
|
||||
@@ -738,7 +738,7 @@ async def openai_stream_to_anthropic_stream(openai_stream_generator, model: str
|
||||
'index': current_block_index,
|
||||
'delta': {'type': 'thinking_delta', 'thinking': reasoning_content},
|
||||
}
|
||||
yield f'event: content_block_delta\ndata: {json.dumps(block_delta)}\n\n'.encode()
|
||||
yield f'event: content_block_delta\ndata: {JSONCodec.dumps(block_delta)}\n\n'.encode()
|
||||
|
||||
# --- Handle text content ---
|
||||
# Anthropic expects text blocks before tool blocks, so skip
|
||||
@@ -750,7 +750,7 @@ async def openai_stream_to_anthropic_stream(openai_stream_generator, model: str
|
||||
'type': 'content_block_stop',
|
||||
'index': current_block_index,
|
||||
}
|
||||
yield f'event: content_block_stop\ndata: {json.dumps(block_stop)}\n\n'.encode()
|
||||
yield f'event: content_block_stop\ndata: {JSONCodec.dumps(block_stop)}\n\n'.encode()
|
||||
thinking_block_open = False
|
||||
current_block_index += 1
|
||||
|
||||
@@ -760,7 +760,7 @@ async def openai_stream_to_anthropic_stream(openai_stream_generator, model: str
|
||||
'index': current_block_index,
|
||||
'content_block': {'type': 'text', 'text': ''},
|
||||
}
|
||||
yield f'event: content_block_start\ndata: {json.dumps(block_start)}\n\n'.encode()
|
||||
yield f'event: content_block_start\ndata: {JSONCodec.dumps(block_start)}\n\n'.encode()
|
||||
text_block_open = True
|
||||
|
||||
block_delta = {
|
||||
@@ -768,7 +768,7 @@ async def openai_stream_to_anthropic_stream(openai_stream_generator, model: str
|
||||
'index': current_block_index,
|
||||
'delta': {'type': 'text_delta', 'text': content},
|
||||
}
|
||||
yield f'event: content_block_delta\ndata: {json.dumps(block_delta)}\n\n'.encode()
|
||||
yield f'event: content_block_delta\ndata: {JSONCodec.dumps(block_delta)}\n\n'.encode()
|
||||
|
||||
# --- Handle tool calls ---
|
||||
# Some providers put tool_calls on the final message object
|
||||
@@ -784,7 +784,7 @@ async def openai_stream_to_anthropic_stream(openai_stream_generator, model: str
|
||||
'type': 'content_block_stop',
|
||||
'index': current_block_index,
|
||||
}
|
||||
yield f'event: content_block_stop\ndata: {json.dumps(block_stop)}\n\n'.encode()
|
||||
yield f'event: content_block_stop\ndata: {JSONCodec.dumps(block_stop)}\n\n'.encode()
|
||||
thinking_block_open = False
|
||||
current_block_index += 1
|
||||
|
||||
@@ -793,7 +793,7 @@ async def openai_stream_to_anthropic_stream(openai_stream_generator, model: str
|
||||
'type': 'content_block_stop',
|
||||
'index': current_block_index,
|
||||
}
|
||||
yield f'event: content_block_stop\ndata: {json.dumps(block_stop)}\n\n'.encode()
|
||||
yield f'event: content_block_stop\ndata: {JSONCodec.dumps(block_stop)}\n\n'.encode()
|
||||
text_block_open = False
|
||||
current_block_index += 1
|
||||
|
||||
@@ -856,7 +856,7 @@ async def openai_stream_to_anthropic_stream(openai_stream_generator, model: str
|
||||
'input': {},
|
||||
},
|
||||
}
|
||||
yield f'event: content_block_start\ndata: {json.dumps(block_start)}\n\n'.encode()
|
||||
yield f'event: content_block_start\ndata: {JSONCodec.dumps(block_start)}\n\n'.encode()
|
||||
current_block_index += 1
|
||||
|
||||
# Buffer arguments and emit as input_json_delta
|
||||
@@ -872,19 +872,19 @@ async def openai_stream_to_anthropic_stream(openai_stream_generator, model: str
|
||||
'partial_json': arguments_chunk,
|
||||
},
|
||||
}
|
||||
yield f'event: content_block_delta\ndata: {json.dumps(block_delta)}\n\n'.encode()
|
||||
yield f'event: content_block_delta\ndata: {JSONCodec.dumps(block_delta)}\n\n'.encode()
|
||||
|
||||
# Close the block once arguments form complete JSON
|
||||
if tool['started'] and not tool['stopped']:
|
||||
try:
|
||||
json.loads(tool['arguments'])
|
||||
JSONCodec.loads(tool['arguments'])
|
||||
tool['stopped'] = True
|
||||
block_stop = {
|
||||
'type': 'content_block_stop',
|
||||
'index': tool['block_index'],
|
||||
}
|
||||
yield f'event: content_block_stop\ndata: {json.dumps(block_stop)}\n\n'.encode()
|
||||
except (json.JSONDecodeError, ValueError):
|
||||
yield f'event: content_block_stop\ndata: {JSONCodec.dumps(block_stop)}\n\n'.encode()
|
||||
except (JSONCodec.JSONDecodeError, ValueError):
|
||||
pass
|
||||
|
||||
# --- Handle finish reason ---
|
||||
@@ -902,7 +902,7 @@ async def openai_stream_to_anthropic_stream(openai_stream_generator, model: str
|
||||
# Close any open thinking block
|
||||
if thinking_block_open:
|
||||
block_stop = {'type': 'content_block_stop', 'index': current_block_index}
|
||||
yield f'event: content_block_stop\ndata: {json.dumps(block_stop)}\n\n'.encode()
|
||||
yield f'event: content_block_stop\ndata: {JSONCodec.dumps(block_stop)}\n\n'.encode()
|
||||
current_block_index += 1
|
||||
|
||||
# Flush any tools that buffered arguments but never emitted a block
|
||||
@@ -921,7 +921,7 @@ async def openai_stream_to_anthropic_stream(openai_stream_generator, model: str
|
||||
'input': {},
|
||||
},
|
||||
}
|
||||
yield f'event: content_block_start\ndata: {json.dumps(block_start)}\n\n'.encode()
|
||||
yield f'event: content_block_start\ndata: {JSONCodec.dumps(block_start)}\n\n'.encode()
|
||||
current_block_index += 1
|
||||
|
||||
if tool['arguments']:
|
||||
@@ -933,18 +933,18 @@ async def openai_stream_to_anthropic_stream(openai_stream_generator, model: str
|
||||
'partial_json': tool['arguments'],
|
||||
},
|
||||
}
|
||||
yield f'event: content_block_delta\ndata: {json.dumps(block_delta)}\n\n'.encode()
|
||||
yield f'event: content_block_delta\ndata: {JSONCodec.dumps(block_delta)}\n\n'.encode()
|
||||
|
||||
# Close any open text block
|
||||
if text_block_open:
|
||||
block_stop = {'type': 'content_block_stop', 'index': current_block_index}
|
||||
yield f'event: content_block_stop\ndata: {json.dumps(block_stop)}\n\n'.encode()
|
||||
yield f'event: content_block_stop\ndata: {JSONCodec.dumps(block_stop)}\n\n'.encode()
|
||||
|
||||
# Close any tool call blocks that are still open
|
||||
for tool in tracked_tool_calls.values():
|
||||
if tool['started'] and not tool['stopped']:
|
||||
block_stop = {'type': 'content_block_stop', 'index': tool['block_index']}
|
||||
yield f'event: content_block_stop\ndata: {json.dumps(block_stop)}\n\n'.encode()
|
||||
yield f'event: content_block_stop\ndata: {JSONCodec.dumps(block_stop)}\n\n'.encode()
|
||||
|
||||
# Emit message_delta with stop reason
|
||||
usage = {'output_tokens': output_tokens}
|
||||
@@ -969,7 +969,7 @@ async def openai_stream_to_anthropic_stream(openai_stream_generator, model: str
|
||||
},
|
||||
'usage': usage,
|
||||
}
|
||||
yield f'event: message_delta\ndata: {json.dumps(message_delta)}\n\n'.encode()
|
||||
yield f'event: message_delta\ndata: {JSONCodec.dumps(message_delta)}\n\n'.encode()
|
||||
|
||||
# Emit message_stop
|
||||
yield f'event: message_stop\ndata: {json.dumps({"type": "message_stop"})}\n\n'.encode()
|
||||
yield f'event: message_stop\ndata: {JSONCodec.dumps({"type": "message_stop"})}\n\n'.encode()
|
||||
|
||||
@@ -4,7 +4,6 @@ import asyncio
|
||||
import base64
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import uuid
|
||||
@@ -40,6 +39,7 @@ from open_webui.models.auths import Auths
|
||||
from open_webui.models.config import Config
|
||||
from open_webui.models.users import Users
|
||||
from open_webui.utils.access_control import has_permission
|
||||
from open_webui.utils.json_codec import JSONCodec
|
||||
from pytz import UTC
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -143,13 +143,13 @@ def get_license_data(app, key):
|
||||
ln, lt = nt(lb)
|
||||
|
||||
aesgcm = AESGCM(kb)
|
||||
p = json.loads(aesgcm.decrypt(ln, lt, None))
|
||||
p = JSONCodec.loads(aesgcm.decrypt(ln, lt, None))
|
||||
pk.verify(base64.b64decode(p['s']), p['p'].encode())
|
||||
|
||||
pb = base64.b64decode(p['p'])
|
||||
pn, pt = nt(pb)
|
||||
|
||||
data = json.loads(aesgcm.decrypt(pn, pt, None).decode())
|
||||
data = JSONCodec.loads(aesgcm.decrypt(pn, pt, None).decode())
|
||||
|
||||
exp = data.get('exp')
|
||||
if exp:
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import random
|
||||
import sys
|
||||
@@ -32,6 +31,7 @@ from open_webui.utils.filter import (
|
||||
get_filter_functions,
|
||||
process_filter_functions,
|
||||
)
|
||||
from open_webui.utils.json_codec import JSONCodec
|
||||
from open_webui.utils.models import check_model_access, get_all_models
|
||||
from open_webui.utils.payload import convert_payload_openai_to_ollama
|
||||
from open_webui.utils.response import (
|
||||
@@ -108,7 +108,7 @@ async def generate_direct_chat_completion(
|
||||
if 'done' in data and data['done']:
|
||||
break # Stop streaming when 'done' is received
|
||||
|
||||
yield f'data: {json.dumps(data)}\n\n'
|
||||
yield f'data: {JSONCodec.dumps(data)}\n\n'
|
||||
elif isinstance(data, str):
|
||||
if 'data:' in data:
|
||||
yield f'{data}\n\n'
|
||||
@@ -249,7 +249,7 @@ async def generate_chat_completion(
|
||||
if form_data.get('stream') == True:
|
||||
|
||||
async def stream_wrapper(stream):
|
||||
yield f'data: {json.dumps({"selected_model_id": selected_model_id})}\n\n'
|
||||
yield f'data: {JSONCodec.dumps({"selected_model_id": selected_model_id})}\n\n'
|
||||
async for chunk in stream:
|
||||
yield chunk
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
from open_webui.utils.json_codec import JSONCodec
|
||||
|
||||
CHAT_VARIABLE_KEY_RE = re.compile(r'^[a-z][a-z0-9_]*$')
|
||||
CHAT_VARIABLE_ANY_RE = re.compile(r'{{\s*chat\.variables\.([^\s|}]+)(?:\s*\|\s*([^}]*))?\s*}}')
|
||||
@@ -64,8 +64,8 @@ def parse_json_value(value: str) -> Any:
|
||||
|
||||
if re.match(r'^[\[{]', value):
|
||||
try:
|
||||
return json.loads(value)
|
||||
except json.JSONDecodeError:
|
||||
return JSONCodec.loads(value)
|
||||
except JSONCodec.JSONDecodeError:
|
||||
return value
|
||||
|
||||
return value
|
||||
@@ -185,7 +185,7 @@ def validate_user_variables(variables: Any) -> dict[str, str]:
|
||||
raise ChatVariablesError('User variables must be an object.')
|
||||
|
||||
try:
|
||||
if len(json.dumps(variables)) > MAX_VARIABLES_JSON_LENGTH:
|
||||
if len(JSONCodec.dumps(variables)) > MAX_VARIABLES_JSON_LENGTH:
|
||||
raise ChatVariablesError('User variables are too large.')
|
||||
except TypeError:
|
||||
raise ChatVariablesError('User variables must be JSON serializable.')
|
||||
@@ -214,7 +214,7 @@ def validate_chat_variables(
|
||||
variables = normalize_chat_variables(variables)
|
||||
|
||||
try:
|
||||
if len(json.dumps(variables)) > MAX_VARIABLES_JSON_LENGTH:
|
||||
if len(JSONCodec.dumps(variables)) > MAX_VARIABLES_JSON_LENGTH:
|
||||
raise ChatVariablesError('Chat variables are too large.')
|
||||
except TypeError:
|
||||
raise ChatVariablesError('Chat variables must be JSON serializable.')
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import uuid
|
||||
from typing import Optional
|
||||
@@ -128,7 +127,7 @@ class JupyterCodeExecuter:
|
||||
# send message
|
||||
msg_id = uuid.uuid4().hex
|
||||
await ws.send(
|
||||
json.dumps(
|
||||
JSONCodec.dumps(
|
||||
{
|
||||
'header': {
|
||||
'msg_id': msg_id,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
@@ -8,6 +7,7 @@ from fastapi.responses import JSONResponse
|
||||
from open_webui.models.chats import Chats
|
||||
from open_webui.models.config import Config
|
||||
from open_webui.utils.chat_id import is_saved_chat_id
|
||||
from open_webui.utils.json_codec import JSONCodec
|
||||
from open_webui.utils.misc import get_content_from_message, get_last_user_message, get_message_list
|
||||
from open_webui.utils.task import (
|
||||
get_task_model_id,
|
||||
@@ -429,7 +429,7 @@ def _response_text(response: Any) -> str:
|
||||
|
||||
if isinstance(response, JSONResponse):
|
||||
try:
|
||||
response = json.loads(response.body.decode('utf-8', 'replace'))
|
||||
response = JSONCodec.loads(response.body.decode('utf-8', 'replace'))
|
||||
except Exception:
|
||||
return ''
|
||||
|
||||
@@ -477,7 +477,7 @@ def _estimate_tokens(value: Any) -> int:
|
||||
|
||||
if not isinstance(value, str):
|
||||
try:
|
||||
value = json.dumps(value, ensure_ascii=False)
|
||||
value = JSONCodec.dumps(value, ensure_ascii=False)
|
||||
except Exception:
|
||||
value = str(value)
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import json
|
||||
import logging
|
||||
import random
|
||||
import urllib.parse
|
||||
@@ -6,6 +5,7 @@ from typing import Optional
|
||||
|
||||
import aiohttp
|
||||
from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL
|
||||
from open_webui.utils.json_codec import JSONCodec
|
||||
from open_webui.utils.session_pool import get_session
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -76,7 +76,7 @@ async def _ws_get_images(ws, workflow, client_id, base_url, api_key):
|
||||
|
||||
async for msg in ws:
|
||||
if msg.type == aiohttp.WSMsgType.TEXT:
|
||||
message = json.loads(msg.data)
|
||||
message = JSONCodec.loads(msg.data)
|
||||
if message['type'] == 'executing':
|
||||
data = message['data']
|
||||
if data['node'] is None and data['prompt_id'] == prompt_id:
|
||||
@@ -188,7 +188,7 @@ def _apply_workflow_nodes(workflow, nodes, model, payload):
|
||||
|
||||
async def comfyui_create_image(model: str, payload: ComfyUICreateImageForm, client_id, base_url, api_key):
|
||||
ws_url = base_url.replace('http://', 'ws://').replace('https://', 'wss://')
|
||||
workflow = json.loads(payload.workflow.workflow)
|
||||
workflow = JSONCodec.loads(payload.workflow.workflow)
|
||||
_apply_workflow_nodes(workflow, payload.workflow.nodes, model, payload)
|
||||
|
||||
headers = {'Authorization': f'Bearer {api_key}'}
|
||||
@@ -229,7 +229,7 @@ class ComfyUIEditImageForm(BaseModel):
|
||||
|
||||
async def comfyui_edit_image(model: str, payload: ComfyUIEditImageForm, client_id, base_url, api_key):
|
||||
ws_url = base_url.replace('http://', 'ws://').replace('https://', 'wss://')
|
||||
workflow = json.loads(payload.workflow.workflow)
|
||||
workflow = JSONCodec.loads(payload.workflow.workflow)
|
||||
_apply_workflow_nodes(workflow, payload.workflow.nodes, model, payload)
|
||||
|
||||
headers = {'Authorization': f'Bearer {api_key}'}
|
||||
|
||||
@@ -19,6 +19,7 @@ from open_webui.env import (
|
||||
LOG_FORMAT,
|
||||
LOGURU_DIAGNOSE,
|
||||
)
|
||||
from open_webui.utils.json_codec import JSONCodec
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from loguru import Message, Record
|
||||
@@ -34,7 +35,7 @@ def stdout_format(record: 'Record') -> str:
|
||||
str: A formatted log string intended for stdout.
|
||||
"""
|
||||
if record['extra']:
|
||||
record['extra']['extra_json'] = json.dumps(record['extra'])
|
||||
record['extra']['extra_json'] = JSONCodec.dumps(record['extra'])
|
||||
extra_format = ' - {extra[extra_json]}'
|
||||
else:
|
||||
extra_format = ''
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
from fastapi import HTTPException
|
||||
|
||||
from open_webui.models.config import Config
|
||||
from open_webui.models.memories import Memories
|
||||
from open_webui.utils.json_codec import JSONCodec
|
||||
from open_webui.utils.misc import add_or_update_system_message, get_content_from_message
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -593,7 +592,7 @@ Conversation:
|
||||
return []
|
||||
|
||||
try:
|
||||
parsed = json.loads(content[start : end + 1])
|
||||
parsed = JSONCodec.loads(content[start : end + 1])
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@ from open_webui.env import (
|
||||
GLOBAL_LOG_LEVEL,
|
||||
RAG_SYSTEM_CONTEXT,
|
||||
)
|
||||
from open_webui.events import EVENTS, publish_event
|
||||
from open_webui.models.access_grants import AccessGrants
|
||||
from open_webui.models.chats import Chats
|
||||
from open_webui.models.config import Config
|
||||
from open_webui.models.folders import Folders
|
||||
@@ -47,7 +49,6 @@ from open_webui.models.models import Models
|
||||
from open_webui.models.notes import Notes
|
||||
from open_webui.models.oauth_sessions import OAuthSessions
|
||||
from open_webui.models.users import UserModel, Users
|
||||
from open_webui.events import EVENTS, publish_event
|
||||
from open_webui.retrieval.utils import get_sources_from_items
|
||||
from open_webui.routers.images import (
|
||||
CreateImageForm,
|
||||
@@ -76,7 +77,6 @@ from open_webui.socket.main import (
|
||||
get_event_emitter,
|
||||
)
|
||||
from open_webui.utils.access_control import has_connection_access, has_permission
|
||||
from open_webui.models.access_grants import AccessGrants
|
||||
from open_webui.utils.access_control.files import get_owner_accessible_folder_files
|
||||
from open_webui.utils.access_control.folders import has_folder_access
|
||||
from open_webui.utils.chat import generate_chat_completion
|
||||
@@ -94,7 +94,6 @@ from open_webui.utils.filter import (
|
||||
get_filter_functions,
|
||||
process_filter_functions,
|
||||
)
|
||||
|
||||
from open_webui.utils.json_codec import JSONCodec
|
||||
from open_webui.utils.mcp.client import MCPClient
|
||||
from open_webui.utils.memory import add_memory_context, review_memory_after_turn
|
||||
@@ -242,7 +241,7 @@ def _split_tool_calls(
|
||||
|
||||
def split_json_objects(raw: str) -> list[str]:
|
||||
if not isinstance(raw, str):
|
||||
raw = '' if raw is None else json.dumps(raw)
|
||||
raw = '' if raw is None else JSONCodec.dumps(raw)
|
||||
|
||||
decoder = json.JSONDecoder()
|
||||
results = []
|
||||
@@ -257,7 +256,7 @@ def _split_tool_calls(
|
||||
_, end = decoder.raw_decode(raw, position)
|
||||
results.append(raw[position:end].strip())
|
||||
position = end
|
||||
except json.JSONDecodeError:
|
||||
except JSONCodec.JSONDecodeError:
|
||||
return [raw]
|
||||
|
||||
return results or [raw]
|
||||
@@ -267,7 +266,7 @@ def _split_tool_calls(
|
||||
function = tool_call.setdefault('function', {})
|
||||
arguments = function.get('arguments')
|
||||
if not isinstance(arguments, str):
|
||||
arguments = '' if arguments is None else json.dumps(arguments)
|
||||
arguments = '' if arguments is None else JSONCodec.dumps(arguments)
|
||||
function['arguments'] = arguments
|
||||
split_arguments = split_json_objects(arguments)
|
||||
|
||||
@@ -302,7 +301,7 @@ def get_citation_source_from_tool_result(
|
||||
try:
|
||||
try:
|
||||
tool_result = JSONCodec.loads(tool_result)
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
except (JSONCodec.JSONDecodeError, TypeError):
|
||||
pass # keep tool_result as-is (e.g. fetch_url returns plain text)
|
||||
if isinstance(tool_result, dict) and 'error' in tool_result:
|
||||
return []
|
||||
@@ -1003,7 +1002,7 @@ async def process_tool_result(
|
||||
if isinstance(text, str):
|
||||
try:
|
||||
text = JSONCodec.loads(text)
|
||||
except json.JSONDecodeError:
|
||||
except JSONCodec.JSONDecodeError:
|
||||
pass
|
||||
tool_response.append(text)
|
||||
elif item.get('type') in ['image', 'audio']:
|
||||
@@ -1031,7 +1030,7 @@ async def process_tool_result(
|
||||
if isinstance(text, str) and text:
|
||||
try:
|
||||
text = JSONCodec.loads(text)
|
||||
except json.JSONDecodeError:
|
||||
except JSONCodec.JSONDecodeError:
|
||||
pass
|
||||
tool_response.append(text)
|
||||
elif resource.get('blob'):
|
||||
@@ -1106,7 +1105,7 @@ async def terminal_event_handler(
|
||||
if isinstance(parsed, str):
|
||||
try:
|
||||
parsed = JSONCodec.loads(parsed)
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
except (JSONCodec.JSONDecodeError, TypeError):
|
||||
pass
|
||||
if isinstance(parsed, dict) and parsed.get('exists') is False:
|
||||
return
|
||||
@@ -1198,7 +1197,7 @@ async def chat_completion_tools_handler(
|
||||
sources = []
|
||||
|
||||
specs = [tool['spec'] for tool in tools.values()]
|
||||
tools_specs = json.dumps(specs, ensure_ascii=False)
|
||||
tools_specs = JSONCodec.dumps(specs, ensure_ascii=False)
|
||||
|
||||
tools_prompt_template = task_config.get('task.tools.prompt_template')
|
||||
if tools_prompt_template != '':
|
||||
@@ -1969,7 +1968,7 @@ def apply_params_to_form_data(form_data, model):
|
||||
try:
|
||||
# Attempt to parse the string as JSON
|
||||
custom_params[key] = JSONCodec.loads(value)
|
||||
except json.JSONDecodeError:
|
||||
except JSONCodec.JSONDecodeError:
|
||||
# If it fails, keep the original string
|
||||
pass
|
||||
|
||||
@@ -3029,7 +3028,7 @@ def get_response_data(response):
|
||||
if isinstance(response.body, bytes):
|
||||
try:
|
||||
response_data = JSONCodec.loads(response.body.decode('utf-8', 'replace'))
|
||||
except json.JSONDecodeError:
|
||||
except JSONCodec.JSONDecodeError:
|
||||
response_data = {'error': {'detail': 'Invalid JSON response'}}
|
||||
else:
|
||||
response_data = response
|
||||
@@ -4471,7 +4470,7 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
delta_tool_call['function']['arguments'] = (
|
||||
''
|
||||
if delta_arguments is None
|
||||
else json.dumps(delta_arguments)
|
||||
else JSONCodec.dumps(delta_arguments)
|
||||
)
|
||||
response_tool_calls.append(delta_tool_call)
|
||||
else:
|
||||
@@ -4486,7 +4485,7 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
|
||||
if delta_arguments is not None:
|
||||
if not isinstance(delta_arguments, str):
|
||||
delta_arguments = json.dumps(delta_arguments)
|
||||
delta_arguments = JSONCodec.dumps(delta_arguments)
|
||||
current_response_tool_call.setdefault('function', {})
|
||||
if not isinstance(
|
||||
current_response_tool_call['function'].get('arguments'),
|
||||
@@ -4874,7 +4873,7 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
'function': {
|
||||
'name': item.get('name', ''),
|
||||
'arguments': (
|
||||
arguments if isinstance(arguments, str) else json.dumps(arguments)
|
||||
arguments if isinstance(arguments, str) else JSONCodec.dumps(arguments)
|
||||
),
|
||||
},
|
||||
}
|
||||
@@ -4963,7 +4962,7 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
except Exception as e:
|
||||
log.debug(e)
|
||||
return None
|
||||
tool_call.setdefault('function', {})['arguments'] = json.dumps(params)
|
||||
tool_call.setdefault('function', {})['arguments'] = JSONCodec.dumps(params)
|
||||
return params
|
||||
|
||||
async def execute_tool_call(tool_call):
|
||||
|
||||
@@ -2,7 +2,6 @@ from __future__ import annotations
|
||||
|
||||
import collections.abc
|
||||
import hashlib
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
import threading
|
||||
@@ -15,6 +14,7 @@ from typing import Callable, Optional, Sequence, Union
|
||||
import aiohttp
|
||||
import mimeparse
|
||||
from open_webui.env import CHAT_STREAM_RESPONSE_CHUNK_MAX_BUFFER_SIZE
|
||||
from open_webui.utils.json_codec import JSONCodec
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
SURROGATE_RE = re.compile('[\ud800-\udfff]')
|
||||
@@ -355,7 +355,7 @@ def convert_output_to_messages(
|
||||
arguments = item.get('arguments', '{}')
|
||||
# Ensure arguments is always a JSON string
|
||||
if not isinstance(arguments, str):
|
||||
arguments = json.dumps(arguments)
|
||||
arguments = JSONCodec.dumps(arguments)
|
||||
pending_tool_calls.append(
|
||||
{
|
||||
'id': item.get('call_id', ''),
|
||||
@@ -822,7 +822,7 @@ def sanitize_data_for_db(obj):
|
||||
# json.dumps is implemented in C and much faster than a Python-level
|
||||
# recursive walk over every leaf string.
|
||||
try:
|
||||
serialized = json.dumps(obj, ensure_ascii=False)
|
||||
serialized = JSONCodec.dumps(obj, ensure_ascii=False)
|
||||
if '\\u0000' not in serialized:
|
||||
serialized.encode('utf-8')
|
||||
return obj
|
||||
@@ -854,7 +854,7 @@ def sanitize_metadata(metadata: dict) -> dict:
|
||||
return None
|
||||
# Last resort: try to see if it's serializable
|
||||
try:
|
||||
json.dumps(obj)
|
||||
JSONCodec.dumps(obj)
|
||||
return obj
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
@@ -864,7 +864,7 @@ def sanitize_metadata(metadata: dict) -> dict:
|
||||
if isinstance(obj, (str, int, float, bool, type(None), dict, list)):
|
||||
return True
|
||||
try:
|
||||
json.dumps(obj)
|
||||
JSONCodec.dumps(obj)
|
||||
return True
|
||||
except (TypeError, ValueError):
|
||||
return False
|
||||
@@ -1018,7 +1018,7 @@ def convert_logit_bias_input_to_json(logit_bias_input) -> str | None:
|
||||
return None
|
||||
|
||||
if isinstance(logit_bias_input, dict):
|
||||
return json.dumps(logit_bias_input)
|
||||
return JSONCodec.dumps(logit_bias_input)
|
||||
|
||||
logit_bias_pairs = logit_bias_input.split(',')
|
||||
logit_bias_json = {}
|
||||
@@ -1028,7 +1028,7 @@ def convert_logit_bias_input_to_json(logit_bias_input) -> str | None:
|
||||
bias = int(bias.strip())
|
||||
bias = 100 if bias > 100 else -100 if bias < -100 else bias
|
||||
logit_bias_json[token] = bias
|
||||
return json.dumps(logit_bias_json)
|
||||
return JSONCodec.dumps(logit_bias_json)
|
||||
|
||||
|
||||
def freeze(value):
|
||||
|
||||
@@ -2,7 +2,6 @@ import asyncio
|
||||
import base64
|
||||
import fnmatch
|
||||
import hashlib
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
import sys
|
||||
@@ -35,8 +34,8 @@ from mcp.shared.auth import (
|
||||
)
|
||||
from open_webui.config import (
|
||||
DEFAULT_USER_ROLE,
|
||||
ENABLE_OAUTH_GROUP_CREATION,
|
||||
ENABLE_OAUTH,
|
||||
ENABLE_OAUTH_GROUP_CREATION,
|
||||
ENABLE_OAUTH_GROUP_MANAGEMENT,
|
||||
ENABLE_OAUTH_ROLE_MANAGEMENT,
|
||||
ENABLE_OAUTH_SIGNUP,
|
||||
@@ -67,7 +66,6 @@ from open_webui.config import (
|
||||
WEBHOOK_URL,
|
||||
)
|
||||
from open_webui.constants import ERROR_MESSAGES
|
||||
from open_webui.events import EVENTS, publish_event
|
||||
from open_webui.env import (
|
||||
AIOHTTP_CLIENT_ALLOW_REDIRECTS,
|
||||
AIOHTTP_CLIENT_SESSION_SSL,
|
||||
@@ -79,6 +77,7 @@ from open_webui.env import (
|
||||
WEBUI_AUTH_COOKIE_SAME_SITE,
|
||||
WEBUI_AUTH_COOKIE_SECURE,
|
||||
)
|
||||
from open_webui.events import EVENTS, publish_event
|
||||
from open_webui.models.auths import Auths
|
||||
from open_webui.models.config import Config
|
||||
from open_webui.models.groups import GroupForm, GroupModel, Groups, GroupUpdateForm
|
||||
@@ -114,6 +113,7 @@ class OAuthClientInformationFull(OAuthClientMetadata):
|
||||
|
||||
|
||||
from open_webui.env import GLOBAL_LOG_LEVEL
|
||||
from open_webui.utils.json_codec import JSONCodec
|
||||
|
||||
logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL)
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -265,7 +265,7 @@ except Exception as e:
|
||||
def encrypt_data(data) -> str:
|
||||
"""Encrypt data for storage"""
|
||||
try:
|
||||
data_json = json.dumps(data)
|
||||
data_json = JSONCodec.dumps(data)
|
||||
encrypted = FERNET.encrypt(data_json.encode()).decode()
|
||||
return encrypted
|
||||
except Exception as e:
|
||||
@@ -277,7 +277,7 @@ def decrypt_data(data: str):
|
||||
"""Decrypt data from storage"""
|
||||
try:
|
||||
decrypted = FERNET.decrypt(data.encode()).decode()
|
||||
return json.loads(decrypted)
|
||||
return JSONCodec.loads(decrypted)
|
||||
except Exception as e:
|
||||
log.error(f'Error decrypting data: {e}')
|
||||
raise
|
||||
@@ -968,7 +968,7 @@ class OAuthClientManager:
|
||||
content_type = resp.headers.get('content-type', '')
|
||||
if 'application/json' in content_type:
|
||||
try:
|
||||
payload = json.loads(response_text)
|
||||
payload = JSONCodec.loads(response_text)
|
||||
error = payload.get('error')
|
||||
error_description = payload.get('error_description', '')
|
||||
except Exception:
|
||||
@@ -1556,7 +1556,7 @@ class OAuthManager:
|
||||
oauth_claim = auth_config.OAUTH_GROUPS_CLAIM
|
||||
|
||||
try:
|
||||
blocked_groups = json.loads(auth_config.OAUTH_BLOCKED_GROUPS)
|
||||
blocked_groups = JSONCodec.loads(auth_config.OAUTH_BLOCKED_GROUPS)
|
||||
except Exception as e:
|
||||
log.exception(f'Error loading OAUTH_BLOCKED_GROUPS: {e}')
|
||||
blocked_groups = []
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import json
|
||||
from typing import Callable, Optional
|
||||
|
||||
from open_webui.utils.chat_variables import render_chat_variables, render_user_variables
|
||||
from open_webui.utils.json_codec import JSONCodec
|
||||
from open_webui.utils.misc import (
|
||||
add_or_update_system_message,
|
||||
deep_update,
|
||||
replace_system_message_content,
|
||||
)
|
||||
from open_webui.utils.chat_variables import render_chat_variables, render_user_variables
|
||||
from open_webui.utils.task import prompt_template, prompt_variables_template
|
||||
|
||||
|
||||
@@ -115,8 +115,8 @@ def apply_model_params_to_body_openai(params: dict, form_data: dict) -> dict:
|
||||
if isinstance(value, str):
|
||||
try:
|
||||
# Attempt to parse the string as JSON
|
||||
custom_params[key] = json.loads(value)
|
||||
except json.JSONDecodeError:
|
||||
custom_params[key] = JSONCodec.loads(value)
|
||||
except JSONCodec.JSONDecodeError:
|
||||
# If it fails, keep the original string
|
||||
pass
|
||||
|
||||
@@ -149,8 +149,8 @@ def apply_model_params_to_body_ollama(params: dict, form_data: dict) -> dict:
|
||||
if isinstance(value, str):
|
||||
try:
|
||||
# Attempt to parse the string as JSON
|
||||
custom_params[key] = json.loads(value)
|
||||
except json.JSONDecodeError:
|
||||
custom_params[key] = JSONCodec.loads(value)
|
||||
except JSONCodec.JSONDecodeError:
|
||||
# If it fails, keep the original string
|
||||
pass
|
||||
|
||||
@@ -198,7 +198,7 @@ def apply_model_params_to_body_ollama(params: dict, form_data: dict) -> dict:
|
||||
Parses a JSON string into a dictionary, handling potential JSONDecodeError.
|
||||
"""
|
||||
try:
|
||||
return json.loads(value)
|
||||
return JSONCodec.loads(value)
|
||||
except Exception as e:
|
||||
return value
|
||||
|
||||
@@ -253,7 +253,7 @@ def convert_messages_openai_to_ollama(messages: list[dict]) -> list[dict]:
|
||||
'id': tool_call.get('id', None),
|
||||
'function': {
|
||||
'name': tool_call.get('function', {}).get('name', ''),
|
||||
'arguments': json.loads(tool_call.get('function', {}).get('arguments', {})),
|
||||
'arguments': JSONCodec.loads(tool_call.get('function', {}).get('arguments', {})),
|
||||
},
|
||||
}
|
||||
ollama_tool_calls.append(ollama_tool_call)
|
||||
@@ -336,7 +336,7 @@ def convert_payload_openai_to_ollama(openai_payload: dict) -> dict:
|
||||
Parses a JSON string into a dictionary, handling potential JSONDecodeError.
|
||||
"""
|
||||
try:
|
||||
return json.loads(value)
|
||||
return JSONCodec.loads(value)
|
||||
except Exception as e:
|
||||
return value
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import json
|
||||
from numbers import Number
|
||||
from uuid import uuid4
|
||||
|
||||
@@ -158,7 +157,7 @@ def convert_ollama_tool_call_to_openai(tool_calls: list) -> list:
|
||||
'type': 'function',
|
||||
'function': {
|
||||
'name': function.get('name', ''),
|
||||
'arguments': json.dumps(function.get('arguments', {})),
|
||||
'arguments': JSONCodec.dumps(function.get('arguments', {})),
|
||||
},
|
||||
}
|
||||
openai_tool_calls.append(openai_tool_call)
|
||||
|
||||
@@ -2,7 +2,6 @@ from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import copy
|
||||
import json
|
||||
import time
|
||||
from datetime import timedelta
|
||||
from uuid import uuid4
|
||||
@@ -16,6 +15,7 @@ from open_webui.models.config import Config
|
||||
from open_webui.models.users import UserModel, Users
|
||||
from open_webui.tasks import create_task, has_active_tasks
|
||||
from open_webui.utils.auth import create_token
|
||||
from open_webui.utils.json_codec import JSONCodec
|
||||
from open_webui.utils.misc import get_message_list
|
||||
from sqlalchemy import select
|
||||
from starlette.datastructures import Headers
|
||||
@@ -647,7 +647,7 @@ async def delegate(
|
||||
return f'Error: {exc}'
|
||||
|
||||
if background:
|
||||
return json.dumps(
|
||||
return JSONCodec.dumps(
|
||||
{
|
||||
'status': 'dispatched',
|
||||
'delegation_id': delegation_id,
|
||||
|
||||
@@ -4,7 +4,6 @@ from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import copy
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
import time
|
||||
@@ -13,15 +12,15 @@ from typing import Literal
|
||||
from uuid import uuid4
|
||||
|
||||
from fastapi import Request
|
||||
from sqlalchemy import select
|
||||
from starlette.datastructures import Headers
|
||||
|
||||
from open_webui.internal.db import get_async_db
|
||||
from open_webui.models.chat_messages import ChatMessages
|
||||
from open_webui.models.chats import Chat, ChatForm, Chats
|
||||
from open_webui.models.users import UserModel, Users
|
||||
from open_webui.tasks import has_active_tasks
|
||||
from open_webui.utils.json_codec import JSONCodec
|
||||
from open_webui.utils.misc import get_message_list
|
||||
from sqlalchemy import select
|
||||
from starlette.datastructures import Headers
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -157,7 +156,7 @@ async def create_timer(
|
||||
if not chat:
|
||||
return 'Error: failed to create timer.'
|
||||
|
||||
return json.dumps(
|
||||
return JSONCodec.dumps(
|
||||
{
|
||||
'status': 'set',
|
||||
'at': datetime.fromtimestamp(due_at / 1_000_000_000, timezone.utc).isoformat().replace('+00:00', 'Z'),
|
||||
|
||||
@@ -4,7 +4,6 @@ import asyncio
|
||||
import base64
|
||||
import copy
|
||||
import inspect
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
@@ -46,7 +45,6 @@ from open_webui.models.config import Config
|
||||
from open_webui.models.groups import Groups
|
||||
from open_webui.models.tools import Tools
|
||||
from open_webui.models.users import UserModel
|
||||
from open_webui.utils.chat_id import is_saved_chat_id
|
||||
from open_webui.tools.builtin import (
|
||||
add_memory,
|
||||
calculate_timestamp,
|
||||
@@ -65,8 +63,8 @@ from open_webui.tools.builtin import (
|
||||
grep_chat_files,
|
||||
grep_knowledge_files,
|
||||
kb_exec,
|
||||
list_chat_files,
|
||||
list_automations,
|
||||
list_chat_files,
|
||||
list_knowledge,
|
||||
list_knowledge_bases,
|
||||
list_memories,
|
||||
@@ -103,7 +101,9 @@ from open_webui.tools.builtin import (
|
||||
write_note,
|
||||
)
|
||||
from open_webui.utils.access_control import has_access, has_connection_access, has_permission
|
||||
from open_webui.utils.chat_id import is_saved_chat_id
|
||||
from open_webui.utils.headers import get_custom_headers, include_user_info_headers
|
||||
from open_webui.utils.json_codec import JSONCodec
|
||||
from open_webui.utils.misc import is_string_allowed
|
||||
from open_webui.utils.plugin import get_tool_contents_cache, get_tools_cache, load_tool_module_by_id
|
||||
from open_webui.utils.terminals import get_terminal_server_url
|
||||
@@ -1141,7 +1141,7 @@ async def set_tool_servers(request: Request):
|
||||
try:
|
||||
if request.app.state.redis is not None:
|
||||
await request.app.state.redis.set(
|
||||
f'{REDIS_KEY_PREFIX}:tool_servers', json.dumps(request.app.state.TOOL_SERVERS)
|
||||
f'{REDIS_KEY_PREFIX}:tool_servers', JSONCodec.dumps(request.app.state.TOOL_SERVERS)
|
||||
)
|
||||
except Exception as e:
|
||||
log.error(f'Error caching tool_servers to Redis: {e}')
|
||||
@@ -1154,7 +1154,7 @@ async def get_tool_servers(request: Request):
|
||||
tool_servers = []
|
||||
if request.app.state.redis is not None:
|
||||
try:
|
||||
tool_servers = json.loads(await request.app.state.redis.get(f'{REDIS_KEY_PREFIX}:tool_servers'))
|
||||
tool_servers = JSONCodec.loads(await request.app.state.redis.get(f'{REDIS_KEY_PREFIX}:tool_servers'))
|
||||
request.app.state.TOOL_SERVERS = tool_servers
|
||||
except Exception as e:
|
||||
log.error(f'Error fetching tool_servers from Redis: {e}')
|
||||
@@ -1286,7 +1286,7 @@ async def set_terminal_servers(request: Request):
|
||||
|
||||
if request.app.state.redis is not None:
|
||||
await request.app.state.redis.set(
|
||||
f'{REDIS_KEY_PREFIX}:terminal_servers', json.dumps(request.app.state.TERMINAL_SERVERS)
|
||||
f'{REDIS_KEY_PREFIX}:terminal_servers', JSONCodec.dumps(request.app.state.TERMINAL_SERVERS)
|
||||
)
|
||||
|
||||
return request.app.state.TERMINAL_SERVERS
|
||||
@@ -1297,7 +1297,7 @@ async def get_terminal_servers(request: Request):
|
||||
terminal_servers = []
|
||||
if request.app.state.redis is not None:
|
||||
try:
|
||||
terminal_servers = json.loads(await request.app.state.redis.get(f'{REDIS_KEY_PREFIX}:terminal_servers'))
|
||||
terminal_servers = JSONCodec.loads(await request.app.state.redis.get(f'{REDIS_KEY_PREFIX}:terminal_servers'))
|
||||
request.app.state.TERMINAL_SERVERS = terminal_servers
|
||||
except Exception as e:
|
||||
log.error(f'Error fetching terminal_servers from Redis: {e}')
|
||||
@@ -1434,8 +1434,8 @@ async def get_tool_server_data(url: str, headers: dict | None) -> dict[str, Any]
|
||||
res = yaml.safe_load(text_content)
|
||||
else:
|
||||
try:
|
||||
res = json.loads(text_content)
|
||||
except json.JSONDecodeError:
|
||||
res = JSONCodec.loads(text_content)
|
||||
except JSONCodec.JSONDecodeError:
|
||||
# Fall back to YAML for non-.yml URLs that aren't valid JSON
|
||||
res = yaml.safe_load(text_content)
|
||||
|
||||
@@ -1491,7 +1491,7 @@ async def get_tool_servers_data(servers: list[dict[str, Any]]) -> list[dict[str,
|
||||
# Use provided JSON spec
|
||||
spec_json = None
|
||||
try:
|
||||
spec_json = json.loads(server.get('spec', ''))
|
||||
spec_json = JSONCodec.loads(server.get('spec', ''))
|
||||
except Exception as e:
|
||||
log.error(f'Error parsing JSON spec for tool server {id}: {e}')
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import base64
|
||||
import hashlib
|
||||
import json
|
||||
import logging
|
||||
from functools import lru_cache
|
||||
|
||||
from cryptography.fernet import Fernet, InvalidToken
|
||||
from open_webui.env import ENABLE_VALVE_ENCRYPTION, WEBUI_SECRET_KEY
|
||||
from open_webui.utils.json_codec import JSONCodec
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -21,7 +21,7 @@ def _fernet() -> Fernet:
|
||||
def encrypt_valves(valves: dict) -> dict | str:
|
||||
if not ENABLE_VALVE_ENCRYPTION:
|
||||
return valves
|
||||
return _fernet().encrypt(json.dumps(valves).encode()).decode()
|
||||
return _fernet().encrypt(JSONCodec.dumps(valves).encode()).decode()
|
||||
|
||||
|
||||
def decrypt_valves(valves) -> dict:
|
||||
@@ -33,8 +33,8 @@ def decrypt_valves(valves) -> dict:
|
||||
return {}
|
||||
|
||||
try:
|
||||
decrypted = json.loads(_fernet().decrypt(valves.encode()).decode())
|
||||
except (InvalidToken, json.JSONDecodeError) as e:
|
||||
decrypted = JSONCodec.loads(_fernet().decrypt(valves.encode()).decode())
|
||||
except (InvalidToken, JSONCodec.JSONDecodeError) as e:
|
||||
log.warning('Failed to decrypt valves: %s', type(e).__name__)
|
||||
return {}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
|
||||
from open_webui.config import WEBUI_FAVICON_URL
|
||||
@@ -9,6 +8,7 @@ from open_webui.env import (
|
||||
VERSION,
|
||||
)
|
||||
from open_webui.retrieval.web.utils import get_ssrf_safe_session, validate_url
|
||||
from open_webui.utils.json_codec import JSONCodec
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -54,7 +54,7 @@ async def post_webhook(name: str, url: str, message: str, event_data: dict, desc
|
||||
if isinstance(user_data, dict):
|
||||
user_dict = user_data
|
||||
else:
|
||||
user_dict = json.loads(user_data)
|
||||
user_dict = JSONCodec.loads(user_data)
|
||||
facts = [{'name': key, 'value': value} for key, value in user_dict.items()]
|
||||
if event_data.get('event'):
|
||||
facts.insert(0, {'name': 'event', 'value': event_data.get('event')})
|
||||
|
||||
Reference in New Issue
Block a user