mirror of
https://github.com/open-webui/open-webui.git
synced 2026-08-29 08:07:34 -05:00
fix: Preserve arrays in metadata + refresh OAuth token before sync
1. process_metadata (vector/utils.py):
- Lists/arrays now preserved as-is (Pinecone supports native arrays)
- Only datetime and dict types converted to strings
- Enables Pinecone queries like: filter: {labels: {$in: ['SENT']}}
- Fixed iteration bug (was modifying dict while iterating)
2. _sync_user_periodic (gmail_auto_sync.py):
- Now uses OAuth manager to get/refresh token before sync
- Prevents 'OAuth token expired' errors during attachment fetching
- Falls back to stored token if refresh fails
This commit is contained in:
@@ -13,16 +13,42 @@ def filter_metadata(metadata: dict[str, any]) -> dict[str, any]:
|
||||
def process_metadata(
|
||||
metadata: dict[str, any],
|
||||
) -> dict[str, any]:
|
||||
for key, value in metadata.items():
|
||||
# Remove large fields
|
||||
if key in KEYS_TO_EXCLUDE:
|
||||
del metadata[key]
|
||||
"""
|
||||
Process metadata for vector storage.
|
||||
|
||||
# Convert non-serializable fields to strings
|
||||
if (
|
||||
isinstance(value, datetime)
|
||||
or isinstance(value, list)
|
||||
or isinstance(value, dict)
|
||||
):
|
||||
- Removes large excluded fields
|
||||
- Converts non-JSON-serializable types (datetime, dict) to strings
|
||||
- Preserves lists/arrays (Pinecone supports array filtering with $in)
|
||||
"""
|
||||
keys_to_delete = []
|
||||
|
||||
for key, value in metadata.items():
|
||||
# Mark large fields for deletion
|
||||
if key in KEYS_TO_EXCLUDE:
|
||||
keys_to_delete.append(key)
|
||||
continue
|
||||
|
||||
# Convert datetime to ISO string
|
||||
if isinstance(value, datetime):
|
||||
metadata[key] = value.isoformat()
|
||||
# Convert dict to string (nested objects not supported in most vector DBs)
|
||||
elif isinstance(value, dict):
|
||||
metadata[key] = str(value)
|
||||
# KEEP lists as-is - Pinecone supports arrays for $in filtering
|
||||
# e.g., filter: {"labels": {"$in": ["SENT"]}}
|
||||
elif isinstance(value, list):
|
||||
# Ensure list items are serializable (strings, numbers, booleans)
|
||||
metadata[key] = [
|
||||
(
|
||||
str(item)
|
||||
if not isinstance(item, (str, int, float, bool, type(None)))
|
||||
else item
|
||||
)
|
||||
for item in value
|
||||
]
|
||||
|
||||
# Delete excluded keys (can't modify dict while iterating)
|
||||
for key in keys_to_delete:
|
||||
del metadata[key]
|
||||
|
||||
return metadata
|
||||
|
||||
@@ -1238,10 +1238,20 @@ async def _sync_user_periodic(user_id: str) -> bool:
|
||||
logger.debug(f"⏭️ No Google OAuth session for user {user_id}")
|
||||
return False
|
||||
|
||||
# Use OAuth token from session
|
||||
# Note: Token refresh happens automatically on next OAuth login
|
||||
# If token is expired, Gmail API will fail and we'll retry on next cycle
|
||||
oauth_token = oauth_session.token
|
||||
# Get refreshed OAuth token using OAuth manager (auto-refreshes if expired)
|
||||
# This is critical for long-running syncs where token may expire mid-process
|
||||
try:
|
||||
from open_webui.main import app
|
||||
|
||||
oauth_token = await app.state.oauth_manager.get_oauth_token(
|
||||
user_id=user_id,
|
||||
session_id=oauth_session.id,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
f"⚠️ Failed to get/refresh OAuth token for user {user_id}: {e}"
|
||||
)
|
||||
oauth_token = oauth_session.token # Fallback to stored token
|
||||
|
||||
# Validation: Check OAuth token exists and has access_token
|
||||
if not oauth_token or not oauth_token.get("access_token"):
|
||||
|
||||
Reference in New Issue
Block a user