mirror of
https://github.com/open-webui/open-webui.git
synced 2026-08-28 05:27:35 +00:00
perf: build info log messages lazily so raising the log level actually saves work (#27837)
Some checks failed
Python CI / Ruff Format (3.11) (push) Has been cancelled
Python CI / Ruff Format (3.12) (push) Has been cancelled
Create and publish Docker images with specific build args / build (map[arch:linux/amd64 runner:ubuntu-latest], map[build_args: free_disk:false name:main suffix:]) (push) Has been cancelled
Create and publish Docker images with specific build args / build (map[arch:linux/amd64 runner:ubuntu-latest], map[build_args:USE_CUDA=true
USE_CUDA_VER=cu126
free_disk:true name:cuda126 suffix:-cuda126]) (push) Has been cancelled
Create and publish Docker images with specific build args / build (map[arch:linux/amd64 runner:ubuntu-latest], map[build_args:USE_CUDA=true free_disk:true name:cuda suffix:-cuda]) (push) Has been cancelled
Create and publish Docker images with specific build args / build (map[arch:linux/amd64 runner:ubuntu-latest], map[build_args:USE_OLLAMA=true free_disk:false name:ollama suffix:-ollama]) (push) Has been cancelled
Create and publish Docker images with specific build args / build (map[arch:linux/amd64 runner:ubuntu-latest], map[build_args:USE_SLIM=true free_disk:false name:slim suffix:-slim]) (push) Has been cancelled
Create and publish Docker images with specific build args / build (map[arch:linux/arm64 runner:ubuntu-24.04-arm], map[build_args: free_disk:false name:main suffix:]) (push) Has been cancelled
Create and publish Docker images with specific build args / build (map[arch:linux/arm64 runner:ubuntu-24.04-arm], map[build_args:USE_CUDA=true
USE_CUDA_VER=cu126
free_disk:true name:cuda126 suffix:-cuda126]) (push) Has been cancelled
Create and publish Docker images with specific build args / build (map[arch:linux/arm64 runner:ubuntu-24.04-arm], map[build_args:USE_CUDA=true free_disk:true name:cuda suffix:-cuda]) (push) Has been cancelled
Create and publish Docker images with specific build args / build (map[arch:linux/arm64 runner:ubuntu-24.04-arm], map[build_args:USE_OLLAMA=true free_disk:false name:ollama suffix:-ollama]) (push) Has been cancelled
Create and publish Docker images with specific build args / build (map[arch:linux/arm64 runner:ubuntu-24.04-arm], map[build_args:USE_SLIM=true free_disk:false name:slim suffix:-slim]) (push) Has been cancelled
Create and publish Docker images with specific build args / merge (map[name:cuda suffix:-cuda]) (push) Has been cancelled
Create and publish Docker images with specific build args / merge (map[name:cuda126 suffix:-cuda126]) (push) Has been cancelled
Create and publish Docker images with specific build args / merge (map[name:main suffix:]) (push) Has been cancelled
Create and publish Docker images with specific build args / merge (map[name:ollama suffix:-ollama]) (push) Has been cancelled
Create and publish Docker images with specific build args / merge (map[name:slim suffix:-slim]) (push) Has been cancelled
Create and publish Docker images with specific build args / notify-helm-charts (push) Has been cancelled
Create and publish Docker images with specific build args / copy-to-dockerhub (, main) (push) Has been cancelled
Create and publish Docker images with specific build args / copy-to-dockerhub (-cuda, cuda) (push) Has been cancelled
Create and publish Docker images with specific build args / copy-to-dockerhub (-cuda126, cuda126) (push) Has been cancelled
Create and publish Docker images with specific build args / copy-to-dockerhub (-ollama, ollama) (push) Has been cancelled
Create and publish Docker images with specific build args / copy-to-dockerhub (-slim, slim) (push) Has been cancelled
Some checks failed
Python CI / Ruff Format (3.11) (push) Has been cancelled
Python CI / Ruff Format (3.12) (push) Has been cancelled
Create and publish Docker images with specific build args / build (map[arch:linux/amd64 runner:ubuntu-latest], map[build_args: free_disk:false name:main suffix:]) (push) Has been cancelled
Create and publish Docker images with specific build args / build (map[arch:linux/amd64 runner:ubuntu-latest], map[build_args:USE_CUDA=true
USE_CUDA_VER=cu126
free_disk:true name:cuda126 suffix:-cuda126]) (push) Has been cancelled
Create and publish Docker images with specific build args / build (map[arch:linux/amd64 runner:ubuntu-latest], map[build_args:USE_CUDA=true free_disk:true name:cuda suffix:-cuda]) (push) Has been cancelled
Create and publish Docker images with specific build args / build (map[arch:linux/amd64 runner:ubuntu-latest], map[build_args:USE_OLLAMA=true free_disk:false name:ollama suffix:-ollama]) (push) Has been cancelled
Create and publish Docker images with specific build args / build (map[arch:linux/amd64 runner:ubuntu-latest], map[build_args:USE_SLIM=true free_disk:false name:slim suffix:-slim]) (push) Has been cancelled
Create and publish Docker images with specific build args / build (map[arch:linux/arm64 runner:ubuntu-24.04-arm], map[build_args: free_disk:false name:main suffix:]) (push) Has been cancelled
Create and publish Docker images with specific build args / build (map[arch:linux/arm64 runner:ubuntu-24.04-arm], map[build_args:USE_CUDA=true
USE_CUDA_VER=cu126
free_disk:true name:cuda126 suffix:-cuda126]) (push) Has been cancelled
Create and publish Docker images with specific build args / build (map[arch:linux/arm64 runner:ubuntu-24.04-arm], map[build_args:USE_CUDA=true free_disk:true name:cuda suffix:-cuda]) (push) Has been cancelled
Create and publish Docker images with specific build args / build (map[arch:linux/arm64 runner:ubuntu-24.04-arm], map[build_args:USE_OLLAMA=true free_disk:false name:ollama suffix:-ollama]) (push) Has been cancelled
Create and publish Docker images with specific build args / build (map[arch:linux/arm64 runner:ubuntu-24.04-arm], map[build_args:USE_SLIM=true free_disk:false name:slim suffix:-slim]) (push) Has been cancelled
Create and publish Docker images with specific build args / merge (map[name:cuda suffix:-cuda]) (push) Has been cancelled
Create and publish Docker images with specific build args / merge (map[name:cuda126 suffix:-cuda126]) (push) Has been cancelled
Create and publish Docker images with specific build args / merge (map[name:main suffix:]) (push) Has been cancelled
Create and publish Docker images with specific build args / merge (map[name:ollama suffix:-ollama]) (push) Has been cancelled
Create and publish Docker images with specific build args / merge (map[name:slim suffix:-slim]) (push) Has been cancelled
Create and publish Docker images with specific build args / notify-helm-charts (push) Has been cancelled
Create and publish Docker images with specific build args / copy-to-dockerhub (, main) (push) Has been cancelled
Create and publish Docker images with specific build args / copy-to-dockerhub (-cuda, cuda) (push) Has been cancelled
Create and publish Docker images with specific build args / copy-to-dockerhub (-cuda126, cuda126) (push) Has been cancelled
Create and publish Docker images with specific build args / copy-to-dockerhub (-ollama, ollama) (push) Has been cancelled
Create and publish Docker images with specific build args / copy-to-dockerhub (-slim, slim) (push) Has been cancelled
Raising GLOBAL_LOG_LEVEL to WARNING buys quieter output but not less work: 241 INFO call sites interpolate their payload into an f-string before the logging call gets to drop it. The heaviest is get_doc, which logs every chunk id and metadata dict in a collection, so on the full-context retrieval path that is the entire knowledge base, once per chat request.
That one line at WARNING, CPython 3.12:
| knowledge base | payload | before | after |
| -------------- | ------- | -------- | ------- |
| top-k of 3 | 1.2 kB | 3.8 us | 0.07 us |
| 500 chunks | 201 kB | 583.6 us | 0.08 us |
| 5000 chunks | 2.0 MB | 5.8 ms | 0.15 us |
The lazy form log.info('query_doc:result %s %s', result.ids, result.metadatas) hands the payload to record.getMessage(), which the InterceptHandler only reaches once a record has passed the level check. Output at INFO is byte-identical. Two sites that already built their message eagerly, one str concat and one % operator, move to the same lazy form.
This commit is contained in:
parent
52145eede9
commit
2d18727ab8
48 changed files with 297 additions and 247 deletions
|
|
@ -276,9 +276,9 @@ def _resolve_ollama_base_url(url: str) -> str:
|
|||
|
||||
if not default.result() and fallback.result():
|
||||
url = url.replace(':11434', ':12434')
|
||||
log.info(f'Ollama port 11434 unreachable on {host}, falling back to 12434')
|
||||
log.info('Ollama port 11434 unreachable on %s, falling back to 12434', host)
|
||||
elif not default.result():
|
||||
log.info(f'Ollama ports 11434 and 12434 both unreachable on {host}')
|
||||
log.info('Ollama ports 11434 and 12434 both unreachable on %s', host)
|
||||
|
||||
return url
|
||||
|
||||
|
|
@ -811,7 +811,7 @@ if VECTOR_DB == 'oracle23ai':
|
|||
'Oracle23ai requires setting ORACLE_WALLET_DIR and ORACLE_WALLET_PASSWORD when using wallet authentication.'
|
||||
)
|
||||
|
||||
log.info(f'VECTOR_DB: {VECTOR_DB}')
|
||||
log.info('VECTOR_DB: %s', VECTOR_DB)
|
||||
|
||||
# S3 Vector
|
||||
S3_VECTOR_BUCKET_NAME = os.getenv('S3_VECTOR_BUCKET_NAME', None)
|
||||
|
|
@ -994,7 +994,7 @@ PDF_EXTRACT_IMAGES = os.getenv('PDF_EXTRACT_IMAGES', 'False').lower() == 'true'
|
|||
PDF_LOADER_MODE = os.getenv('PDF_LOADER_MODE', 'page')
|
||||
|
||||
RAG_EMBEDDING_MODEL = os.getenv('RAG_EMBEDDING_MODEL', 'sentence-transformers/all-MiniLM-L6-v2')
|
||||
log.info(f'Embedding model set: {RAG_EMBEDDING_MODEL}')
|
||||
log.info('Embedding model set: %s', RAG_EMBEDDING_MODEL)
|
||||
|
||||
RAG_TOKENIZER_MODEL = os.getenv('RAG_TOKENIZER_MODEL', '')
|
||||
|
||||
|
|
@ -1022,7 +1022,7 @@ RAG_RERANKING_ENGINE = os.getenv('RAG_RERANKING_ENGINE', '')
|
|||
|
||||
RAG_RERANKING_MODEL = os.getenv('RAG_RERANKING_MODEL', '')
|
||||
if RAG_RERANKING_MODEL != '':
|
||||
log.info(f'Reranking model set: {RAG_RERANKING_MODEL}')
|
||||
log.info('Reranking model set: %s', RAG_RERANKING_MODEL)
|
||||
|
||||
|
||||
RAG_RERANKING_MODEL_AUTO_UPDATE = (
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ if FROM_INIT_PY:
|
|||
|
||||
# Check if the data directory exists in the package directory
|
||||
if DATA_DIR.exists() and DATA_DIR != NEW_DATA_DIR:
|
||||
log.info(f'Moving {DATA_DIR} to {NEW_DATA_DIR}')
|
||||
log.info('Moving %s to %s', DATA_DIR, NEW_DATA_DIR)
|
||||
for item in DATA_DIR.iterdir():
|
||||
dest = NEW_DATA_DIR / item.name
|
||||
if item.is_dir():
|
||||
|
|
|
|||
|
|
@ -425,13 +425,13 @@ async def lifespan(app: FastAPI):
|
|||
log.info('Initializing tool servers...')
|
||||
try:
|
||||
await set_tool_servers(mock_request)
|
||||
log.info(f'Initialized {len(app.state.TOOL_SERVERS)} tool server(s)')
|
||||
log.info('Initialized %s tool server(s)', len(app.state.TOOL_SERVERS))
|
||||
except Exception as e:
|
||||
log.warning(f'Failed to initialize tool servers at startup: {e}')
|
||||
|
||||
try:
|
||||
await set_terminal_servers(mock_request)
|
||||
log.info(f'Initialized {len(app.state.TERMINAL_SERVERS)} terminal server(s)')
|
||||
log.info('Initialized %s terminal server(s)', len(app.state.TERMINAL_SERVERS))
|
||||
except Exception as e:
|
||||
log.warning(f'Failed to initialize terminal servers at startup: {e}')
|
||||
|
||||
|
|
@ -2594,7 +2594,7 @@ async def register_client(request, client_id: str) -> bool:
|
|||
**apply_connection_oauth_options(connection, oauth_client_info.model_dump(mode='json'))
|
||||
)
|
||||
oauth_client_manager.add_client(client_id, oauth_client_info)
|
||||
log.info(f'Re-registered OAuth client {client_id} for tool server')
|
||||
log.info('Re-registered OAuth client %s for tool server', client_id)
|
||||
return True
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1935,7 +1935,7 @@ class ChatTable:
|
|||
result = await session.execute(stmt)
|
||||
all_chats = result.scalars().all()
|
||||
|
||||
log.info(f'The number of chats: {len(all_chats)}')
|
||||
log.info('The number of chats: %s', len(all_chats))
|
||||
|
||||
# Validate and return chats
|
||||
return [ChatModel.model_validate(chat) for chat in all_chats]
|
||||
|
|
@ -2100,7 +2100,7 @@ class ChatTable:
|
|||
|
||||
bind = await session.connection()
|
||||
dialect_name = bind.dialect.name
|
||||
log.info(f'DB dialect name: {dialect_name}')
|
||||
log.info('DB dialect name: %s', dialect_name)
|
||||
if dialect_name == 'sqlite':
|
||||
stmt = stmt.filter(
|
||||
text(f"EXISTS (SELECT 1 FROM json_each(Chat.meta, '$.tags') WHERE json_each.value = :tag_id)")
|
||||
|
|
@ -2227,7 +2227,7 @@ class ChatTable:
|
|||
result = await session.execute(stmt.where(Chat.meta['internal'].as_boolean().is_not(True)))
|
||||
count = result.scalar()
|
||||
|
||||
log.info(f"Count of chats for folder '{folder_id}': {count}")
|
||||
log.info("Count of chats for folder '%s': %s", folder_id, count)
|
||||
return count
|
||||
|
||||
async def count_chats_by_folder_ids_and_user_id(
|
||||
|
|
@ -2241,7 +2241,7 @@ class ChatTable:
|
|||
result = await session.execute(stmt.where(Chat.meta['internal'].as_boolean().is_not(True)))
|
||||
count = result.scalar()
|
||||
|
||||
log.info(f"Count of chats for folders '{folder_ids}': {count}")
|
||||
log.info("Count of chats for folders '%s': %s", folder_ids, count)
|
||||
return count
|
||||
|
||||
async def delete_tag_by_id_and_user_id_and_tag_name(
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ class DatalabMarkerLoader:
|
|||
response = requests.get(url, headers=headers)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
log.info(f'Marker API status check for request {request_id}: {result}')
|
||||
log.info('Marker API status check for request %s: %s', request_id, result)
|
||||
return result
|
||||
except requests.HTTPError as e:
|
||||
log.error(f'Error checking Marker request status: {e}')
|
||||
|
|
@ -104,7 +104,10 @@ class DatalabMarkerLoader:
|
|||
form_data['additional_config'] = self.additional_config
|
||||
|
||||
log.info(
|
||||
f"Datalab Marker POST request parameters: {{'filename': '{filename}', 'mime_type': '{mime_type}', **{form_data}}}"
|
||||
"Datalab Marker POST request parameters: {'filename': '%s', 'mime_type': '%s', **%s}",
|
||||
filename,
|
||||
mime_type,
|
||||
form_data,
|
||||
)
|
||||
|
||||
try:
|
||||
|
|
@ -168,7 +171,7 @@ class DatalabMarkerLoader:
|
|||
'total_cost',
|
||||
)
|
||||
}
|
||||
log.info(f'Marker processing completed successfully: {json.dumps(summary, indent=2)}')
|
||||
log.info('Marker processing completed successfully: %s', json.dumps(summary, indent=2))
|
||||
break
|
||||
|
||||
if status_val == 'failed' or success_val is False:
|
||||
|
|
@ -235,7 +238,7 @@ class DatalabMarkerLoader:
|
|||
try:
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
f.write(full_text)
|
||||
log.info(f'Saved Marker output to: {output_path}')
|
||||
log.info('Saved Marker output to: %s', output_path)
|
||||
except Exception as e:
|
||||
log.warning(f'Failed to write marker output to disk: {e}')
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ class MinerULoader:
|
|||
Load document using Local API (synchronous).
|
||||
Posts file to /file_parse endpoint and gets immediate response.
|
||||
"""
|
||||
log.info(f'Using MinerU Local API at {self.api_url}')
|
||||
log.info('Using MinerU Local API at %s', self.api_url)
|
||||
|
||||
filename = os.path.basename(self.file_path)
|
||||
|
||||
|
|
@ -97,7 +97,7 @@ class MinerULoader:
|
|||
with open(self.file_path, 'rb') as f:
|
||||
files = {'files': (filename, f, 'application/octet-stream')}
|
||||
|
||||
log.info(f'Sending file to MinerU Local API: {filename}')
|
||||
log.info('Sending file to MinerU Local API: %s', filename)
|
||||
log.debug('Local API parameters: %s', form_data)
|
||||
|
||||
response = requests.post(
|
||||
|
|
@ -163,7 +163,7 @@ class MinerULoader:
|
|||
detail='MinerU returned empty markdown content',
|
||||
)
|
||||
|
||||
log.info(f'Successfully parsed document with MinerU Local API: {filename}')
|
||||
log.info('Successfully parsed document with MinerU Local API: %s', filename)
|
||||
|
||||
# Create metadata
|
||||
metadata = {
|
||||
|
|
@ -180,7 +180,7 @@ class MinerULoader:
|
|||
Load document using Cloud API (asynchronous).
|
||||
Uses batch upload endpoint to avoid need for public file URLs.
|
||||
"""
|
||||
log.info(f'Using MinerU Cloud API at {self.api_url}')
|
||||
log.info('Using MinerU Cloud API at %s', self.api_url)
|
||||
|
||||
filename = os.path.basename(self.file_path)
|
||||
|
||||
|
|
@ -196,7 +196,7 @@ class MinerULoader:
|
|||
# Step 4: Download and extract markdown from ZIP
|
||||
markdown_content = self._download_and_extract_zip(result['full_zip_url'], filename)
|
||||
|
||||
log.info(f'Successfully parsed document with MinerU Cloud API: {filename}')
|
||||
log.info('Successfully parsed document with MinerU Cloud API: %s', filename)
|
||||
|
||||
# Create metadata
|
||||
metadata = {
|
||||
|
|
@ -232,7 +232,7 @@ class MinerULoader:
|
|||
if self.page_ranges:
|
||||
request_body['files'][0]['page_ranges'] = self.page_ranges
|
||||
|
||||
log.info(f'Requesting upload URL for: {filename}')
|
||||
log.info('Requesting upload URL for: %s', filename)
|
||||
log.debug('Cloud API request body: %s', request_body)
|
||||
|
||||
try:
|
||||
|
|
@ -284,7 +284,7 @@ class MinerULoader:
|
|||
)
|
||||
|
||||
upload_url = file_urls[0]
|
||||
log.info(f'Received upload URL for batch: {batch_id}')
|
||||
log.info('Received upload URL for batch: %s', batch_id)
|
||||
|
||||
return batch_id, upload_url
|
||||
|
||||
|
|
@ -334,7 +334,7 @@ class MinerULoader:
|
|||
max_iterations = 300 # 10 minutes max (2 seconds per iteration)
|
||||
poll_interval = 2 # seconds
|
||||
|
||||
log.info(f'Polling batch status: {batch_id}')
|
||||
log.info('Polling batch status: %s', batch_id)
|
||||
|
||||
for iteration in range(max_iterations):
|
||||
try:
|
||||
|
|
@ -393,7 +393,7 @@ class MinerULoader:
|
|||
state = file_result.get('state')
|
||||
|
||||
if state == 'done':
|
||||
log.info(f'Processing complete for {filename}')
|
||||
log.info('Processing complete for %s', filename)
|
||||
return file_result
|
||||
elif state == 'failed':
|
||||
error_msg = file_result.get('err_msg', 'Unknown error')
|
||||
|
|
@ -404,7 +404,7 @@ class MinerULoader:
|
|||
elif state in ['waiting-file', 'pending', 'running', 'converting']:
|
||||
# Still processing
|
||||
if iteration % 10 == 0: # Log every 20 seconds
|
||||
log.info(f'Processing status: {state} (iteration {iteration + 1}/{max_iterations})')
|
||||
log.info('Processing status: %s (iteration %s/%s)', state, iteration + 1, max_iterations)
|
||||
time.sleep(poll_interval)
|
||||
else:
|
||||
log.warning(f'Unknown state: {state}')
|
||||
|
|
@ -421,7 +421,7 @@ class MinerULoader:
|
|||
Download ZIP file from CDN and extract markdown content.
|
||||
Returns the markdown content as a string.
|
||||
"""
|
||||
log.info(f'Downloading results from: {zip_url}')
|
||||
log.info('Downloading results from: %s', zip_url)
|
||||
|
||||
try:
|
||||
response = requests.get(zip_url, timeout=60)
|
||||
|
|
@ -452,7 +452,7 @@ class MinerULoader:
|
|||
read_errors = []
|
||||
|
||||
for member in md_members:
|
||||
log.info(f'Found markdown file in ZIP: {member.filename}')
|
||||
log.info('Found markdown file in ZIP: %s', member.filename)
|
||||
try:
|
||||
with zip_ref.open(member, 'r') as f:
|
||||
if self.max_markdown_bytes is None:
|
||||
|
|
@ -515,5 +515,5 @@ class MinerULoader:
|
|||
detail='Extracted markdown content is empty',
|
||||
)
|
||||
|
||||
log.info(f'Successfully extracted markdown content ({len(markdown_content)} characters)')
|
||||
log.info('Successfully extracted markdown content (%s characters)', len(markdown_content))
|
||||
return markdown_content
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ class MistralLoader:
|
|||
file_id = response_data.get('id')
|
||||
if not file_id:
|
||||
raise ValueError('File ID not found in upload response.')
|
||||
log.info(f'File uploaded successfully. File ID: {file_id}')
|
||||
log.info('File uploaded successfully. File ID: %s', file_id)
|
||||
return file_id
|
||||
except Exception as e:
|
||||
log.error(f'Failed to upload file: {e}')
|
||||
|
|
@ -305,12 +305,12 @@ class MistralLoader:
|
|||
if not file_id:
|
||||
raise ValueError('File ID not found in upload response.')
|
||||
|
||||
log.info(f'File uploaded successfully. File ID: {file_id}')
|
||||
log.info('File uploaded successfully. File ID: %s', file_id)
|
||||
return file_id
|
||||
|
||||
def _get_signed_url(self, file_id: str) -> str:
|
||||
"""Retrieves a temporary signed URL for the uploaded file (sync version)."""
|
||||
log.info(f'Getting signed URL for file ID: {file_id}')
|
||||
log.info('Getting signed URL for file ID: %s', file_id)
|
||||
url = f'{self.base_url}/files/{file_id}/url'
|
||||
params = {'expiry': 1}
|
||||
signed_url_headers = {**self.headers, 'Accept': 'application/json'}
|
||||
|
|
@ -421,7 +421,7 @@ class MistralLoader:
|
|||
ocr_response = await self._handle_response_async(response)
|
||||
|
||||
processing_time = time.time() - start_time
|
||||
log.info(f'OCR processing completed in {processing_time:.2f}s')
|
||||
log.info('OCR processing completed in %.2fs', processing_time)
|
||||
|
||||
return ocr_response
|
||||
|
||||
|
|
@ -434,13 +434,13 @@ class MistralLoader:
|
|||
|
||||
def _delete_file(self, file_id: str) -> None:
|
||||
"""Deletes the file from Mistral storage (sync version)."""
|
||||
log.info(f'Deleting uploaded file ID: {file_id}')
|
||||
log.info('Deleting uploaded file ID: %s', file_id)
|
||||
url = f'{self.base_url}/files/{file_id}'
|
||||
|
||||
try:
|
||||
response = requests.delete(url, headers=self.headers, timeout=self.cleanup_timeout)
|
||||
delete_response = self._handle_response(response)
|
||||
log.info(f'File deleted successfully: {delete_response}')
|
||||
log.info('File deleted successfully: %s', delete_response)
|
||||
except Exception as e:
|
||||
# Log error but don't necessarily halt execution if deletion fails
|
||||
log.error(f'Failed to delete file ID {file_id}: {e}')
|
||||
|
|
@ -551,7 +551,7 @@ class MistralLoader:
|
|||
)
|
||||
|
||||
if skipped_pages > 0:
|
||||
log.info(f'Processed {len(documents)} pages, skipped {skipped_pages} empty/invalid pages')
|
||||
log.info('Processed %s pages, skipped %s empty/invalid pages', len(documents), skipped_pages)
|
||||
|
||||
if not documents:
|
||||
# Case where pages existed but none had valid markdown/index
|
||||
|
|
@ -584,7 +584,7 @@ class MistralLoader:
|
|||
if self.use_base64:
|
||||
documents = self._process_results(self._process_ocr(self._get_file_data_url()))
|
||||
total_time = time.time() - start_time
|
||||
log.info(f'Sync OCR workflow completed in {total_time:.2f}s, produced {len(documents)} documents')
|
||||
log.info('Sync OCR workflow completed in %.2fs, produced %s documents', total_time, len(documents))
|
||||
return documents
|
||||
|
||||
# 1. Upload file
|
||||
|
|
@ -600,7 +600,7 @@ class MistralLoader:
|
|||
documents = self._process_results(ocr_response)
|
||||
|
||||
total_time = time.time() - start_time
|
||||
log.info(f'Sync OCR workflow completed in {total_time:.2f}s, produced {len(documents)} documents')
|
||||
log.info('Sync OCR workflow completed in %.2fs, produced %s documents', total_time, len(documents))
|
||||
|
||||
return documents
|
||||
|
||||
|
|
@ -642,7 +642,7 @@ class MistralLoader:
|
|||
ocr_response = await self._process_ocr_async(session, self._get_file_data_url())
|
||||
documents = self._process_results(ocr_response)
|
||||
total_time = time.time() - start_time
|
||||
log.info(f'Async OCR workflow completed in {total_time:.2f}s, produced {len(documents)} documents')
|
||||
log.info('Async OCR workflow completed in %.2fs, produced %s documents', total_time, len(documents))
|
||||
return documents
|
||||
|
||||
# 1. Upload file with streaming
|
||||
|
|
@ -658,7 +658,7 @@ class MistralLoader:
|
|||
documents = self._process_results(ocr_response)
|
||||
|
||||
total_time = time.time() - start_time
|
||||
log.info(f'Async OCR workflow completed in {total_time:.2f}s, produced {len(documents)} documents')
|
||||
log.info('Async OCR workflow completed in %.2fs, produced %s documents', total_time, len(documents))
|
||||
|
||||
return documents
|
||||
|
||||
|
|
@ -701,7 +701,7 @@ class MistralLoader:
|
|||
if not loaders:
|
||||
return []
|
||||
|
||||
log.info(f'Starting concurrent processing of {len(loaders)} files with max {max_concurrent} concurrent')
|
||||
log.info('Starting concurrent processing of %s files with max %s concurrent', len(loaders), max_concurrent)
|
||||
start_time = time.time()
|
||||
|
||||
# Use semaphore to control concurrency
|
||||
|
|
@ -741,9 +741,11 @@ class MistralLoader:
|
|||
failure_count = len(results) - success_count
|
||||
|
||||
log.info(
|
||||
f'Batch processing completed in {total_time:.2f}s: '
|
||||
f'{success_count} files succeeded, {failure_count} files failed, '
|
||||
f'produced {total_docs} total documents'
|
||||
'Batch processing completed in %.2fs: %s files succeeded, %s files failed, produced %s total documents',
|
||||
total_time,
|
||||
success_count,
|
||||
failure_count,
|
||||
total_docs,
|
||||
)
|
||||
|
||||
return processed_results
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ class PaddleOCRVLLoader:
|
|||
self.file_name = os.path.basename(file_path)
|
||||
|
||||
def load(self) -> List[Document]:
|
||||
log.info(f'Processing with PaddleOCR-vl: {self.file_path}')
|
||||
log.info('Processing with PaddleOCR-vl: %s', self.file_path)
|
||||
|
||||
try:
|
||||
with open(self.file_path, 'rb') as file:
|
||||
|
|
@ -96,7 +96,7 @@ class PaddleOCRVLLoader:
|
|||
)
|
||||
|
||||
if skipped_pages > 0:
|
||||
log.info(f'PaddleOCR-vl: Processed {len(documents)} pages, skipped {skipped_pages} empty pages.')
|
||||
log.info('PaddleOCR-vl: Processed %s pages, skipped %s empty pages.', len(documents), skipped_pages)
|
||||
|
||||
if not documents:
|
||||
log.warning('No valid text content found by PaddleOCR-vl.')
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ class YoutubeLoader:
|
|||
log.debug("No transcript found for language '%s'", lang)
|
||||
continue
|
||||
except Exception as e:
|
||||
log.info(f"Error finding transcript for language '{lang}'")
|
||||
log.info("Error finding transcript for language '%s'", lang)
|
||||
raise e
|
||||
|
||||
# If we get here, all languages failed
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ class ExternalReranker(BaseReranker):
|
|||
}
|
||||
|
||||
try:
|
||||
log.info(f'ExternalReranker:predict:model {self.model}')
|
||||
log.info(f'ExternalReranker:predict:query {query}')
|
||||
log.info('ExternalReranker:predict:model %s', self.model)
|
||||
log.info('ExternalReranker:predict:query %s', query)
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
|
|
|
|||
|
|
@ -318,7 +318,7 @@ def query_doc(collection_name: str, query_embedding: list[float], k: int, user:
|
|||
)
|
||||
|
||||
if result:
|
||||
log.info(f'query_doc:result {result.ids} {result.metadatas}')
|
||||
log.info('query_doc:result %s %s', result.ids, result.metadatas)
|
||||
|
||||
return result
|
||||
except Exception as e:
|
||||
|
|
@ -332,7 +332,7 @@ def get_doc(collection_name: str, user: UserModel = None):
|
|||
result = VECTOR_DB_CLIENT.get(collection_name=collection_name)
|
||||
|
||||
if result:
|
||||
log.info(f'query_doc:result {result.ids} {result.metadatas}')
|
||||
log.info('query_doc:result %s %s', result.ids, result.metadatas)
|
||||
|
||||
return result
|
||||
except Exception as e:
|
||||
|
|
@ -585,7 +585,7 @@ async def query_doc_with_hybrid_search(
|
|||
'metadatas': [metadatas],
|
||||
}
|
||||
|
||||
log.info('query_doc_with_hybrid_search:result ' + f'{result["metadatas"]} {result["distances"]}')
|
||||
log.info('query_doc_with_hybrid_search:result %s %s', result['metadatas'], result['distances'])
|
||||
return result
|
||||
except Exception as e:
|
||||
log.exception(f'Error querying doc {collection_name} with hybrid search: {e}')
|
||||
|
|
@ -812,7 +812,7 @@ async def query_collection_with_hybrid_search(
|
|||
|
||||
collection_results = dict(await asyncio.gather(*(_fetch_collection(name) for name in collection_names)))
|
||||
|
||||
log.info(f'Starting hybrid search for {len(queries)} queries in {len(collection_names)} collections...')
|
||||
log.info('Starting hybrid search for %s queries in %s collections...', len(queries), len(collection_names))
|
||||
|
||||
async def process_query(collection_name, query):
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ class MilvusClient(VectorDBBase):
|
|||
index_type = MILVUS_INDEX_TYPE.upper()
|
||||
metric_type = MILVUS_METRIC_TYPE.upper()
|
||||
|
||||
log.info(f'Using Milvus index type: {index_type}, metric type: {metric_type}')
|
||||
log.info('Using Milvus index type: %s, metric type: %s', index_type, metric_type)
|
||||
|
||||
index_creation_params = {}
|
||||
if index_type == 'HNSW':
|
||||
|
|
@ -133,18 +133,18 @@ class MilvusClient(VectorDBBase):
|
|||
'M': MILVUS_HNSW_M,
|
||||
'efConstruction': MILVUS_HNSW_EFCONSTRUCTION,
|
||||
}
|
||||
log.info(f'HNSW params: {index_creation_params}')
|
||||
log.info('HNSW params: %s', index_creation_params)
|
||||
elif index_type == 'IVF_FLAT':
|
||||
index_creation_params = {'nlist': MILVUS_IVF_FLAT_NLIST}
|
||||
log.info(f'IVF_FLAT params: {index_creation_params}')
|
||||
log.info('IVF_FLAT params: %s', index_creation_params)
|
||||
elif index_type == 'DISKANN':
|
||||
index_creation_params = {
|
||||
'max_degree': MILVUS_DISKANN_MAX_DEGREE,
|
||||
'search_list_size': MILVUS_DISKANN_SEARCH_LIST_SIZE,
|
||||
}
|
||||
log.info(f'DISKANN params: {index_creation_params}')
|
||||
log.info('DISKANN params: %s', index_creation_params)
|
||||
elif index_type in ['FLAT', 'AUTOINDEX']:
|
||||
log.info(f'Using {index_type} index with no specific build-time params.')
|
||||
log.info('Using %s index with no specific build-time params.', index_type)
|
||||
else:
|
||||
log.warning(
|
||||
f"Unsupported MILVUS_INDEX_TYPE: '{index_type}'. "
|
||||
|
|
@ -167,7 +167,11 @@ class MilvusClient(VectorDBBase):
|
|||
index_params=index_params,
|
||||
)
|
||||
log.info(
|
||||
f"Successfully created collection '{self.collection_prefix}_{collection_name}' with index type '{index_type}' and metric '{metric_type}'."
|
||||
"Successfully created collection '%s_%s' with index type '%s' and metric '%s'.",
|
||||
self.collection_prefix,
|
||||
collection_name,
|
||||
index_type,
|
||||
metric_type,
|
||||
)
|
||||
|
||||
def has_collection(self, collection_name: str) -> bool:
|
||||
|
|
@ -220,7 +224,11 @@ class MilvusClient(VectorDBBase):
|
|||
|
||||
try:
|
||||
log.info(
|
||||
f"Querying collection {self.collection_prefix}_{collection_name} with filter: '{filter_string}', limit: {limit}"
|
||||
"Querying collection %s_%s with filter: '%s', limit: %s",
|
||||
self.collection_prefix,
|
||||
collection_name,
|
||||
filter_string,
|
||||
limit,
|
||||
)
|
||||
|
||||
iterator = self.client.query_iterator(
|
||||
|
|
@ -265,7 +273,7 @@ class MilvusClient(VectorDBBase):
|
|||
# Insert the items into the collection, if the collection does not exist, it will be created.
|
||||
collection_name = collection_name.replace('-', '_')
|
||||
if not self.client.has_collection(collection_name=f'{self.collection_prefix}_{collection_name}'):
|
||||
log.info(f'Collection {self.collection_prefix}_{collection_name} does not exist. Creating now.')
|
||||
log.info('Collection %s_%s does not exist. Creating now.', self.collection_prefix, collection_name)
|
||||
if not items:
|
||||
log.error(
|
||||
f'Cannot create collection {self.collection_prefix}_{collection_name} without items to determine dimension.'
|
||||
|
|
@ -273,7 +281,7 @@ class MilvusClient(VectorDBBase):
|
|||
raise ValueError('Cannot create Milvus collection without items to determine vector dimension.')
|
||||
self._create_collection(collection_name=collection_name, dimension=len(items[0]['vector']))
|
||||
|
||||
log.info(f'Inserting {len(items)} items into collection {self.collection_prefix}_{collection_name}.')
|
||||
log.info('Inserting %s items into collection %s_%s.', len(items), self.collection_prefix, collection_name)
|
||||
data = []
|
||||
for item in items:
|
||||
text = item['text'] or ''
|
||||
|
|
@ -301,7 +309,9 @@ class MilvusClient(VectorDBBase):
|
|||
# Update the items in the collection, if the items are not present, insert them. If the collection does not exist, it will be created.
|
||||
collection_name = collection_name.replace('-', '_')
|
||||
if not self.client.has_collection(collection_name=f'{self.collection_prefix}_{collection_name}'):
|
||||
log.info(f'Collection {self.collection_prefix}_{collection_name} does not exist for upsert. Creating now.')
|
||||
log.info(
|
||||
'Collection %s_%s does not exist for upsert. Creating now.', self.collection_prefix, collection_name
|
||||
)
|
||||
if not items:
|
||||
log.error(
|
||||
f'Cannot create collection {self.collection_prefix}_{collection_name} for upsert without items to determine dimension.'
|
||||
|
|
@ -311,7 +321,7 @@ class MilvusClient(VectorDBBase):
|
|||
)
|
||||
self._create_collection(collection_name=collection_name, dimension=len(items[0]['vector']))
|
||||
|
||||
log.info(f'Upserting {len(items)} items into collection {self.collection_prefix}_{collection_name}.')
|
||||
log.info('Upserting %s items into collection %s_%s.', len(items), self.collection_prefix, collection_name)
|
||||
data = []
|
||||
for item in items:
|
||||
text = item['text'] or ''
|
||||
|
|
@ -348,7 +358,7 @@ class MilvusClient(VectorDBBase):
|
|||
return None
|
||||
|
||||
if ids:
|
||||
log.info(f'Deleting items by IDs from {self.collection_prefix}_{collection_name}. IDs: {ids}')
|
||||
log.info('Deleting items by IDs from %s_%s. IDs: %s', self.collection_prefix, collection_name, ids)
|
||||
return self.client.delete(
|
||||
collection_name=f'{self.collection_prefix}_{collection_name}',
|
||||
ids=ids,
|
||||
|
|
@ -356,7 +366,10 @@ class MilvusClient(VectorDBBase):
|
|||
elif filter:
|
||||
filter_string = ' && '.join([f'metadata["{key}"] == {JSONCodec.dumps(value)}' for key, value in filter.items()])
|
||||
log.info(
|
||||
f'Deleting items by filter from {self.collection_prefix}_{collection_name}. Filter: {filter_string}'
|
||||
'Deleting items by filter from %s_%s. Filter: %s',
|
||||
self.collection_prefix,
|
||||
collection_name,
|
||||
filter_string,
|
||||
)
|
||||
return self.client.delete(
|
||||
collection_name=f'{self.collection_prefix}_{collection_name}',
|
||||
|
|
@ -378,7 +391,7 @@ class MilvusClient(VectorDBBase):
|
|||
try:
|
||||
self.client.drop_collection(collection_name=collection_name_full)
|
||||
deleted_collections.append(collection_name_full)
|
||||
log.info(f'Deleted collection: {collection_name_full}')
|
||||
log.info('Deleted collection: %s', collection_name_full)
|
||||
except Exception as e:
|
||||
log.error(f'Error deleting collection {collection_name_full}: {e}')
|
||||
log.info(f'Milvus reset complete. Deleted collections: {deleted_collections}')
|
||||
log.info('Milvus reset complete. Deleted collections: %s', deleted_collections)
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ class MilvusClient(VectorDBBase):
|
|||
# The index only accelerates resource_id filters; never fail
|
||||
# collection creation over it.
|
||||
log.warning(f'Could not create {RESOURCE_ID_FIELD} index on {mt_collection_name}: {e}')
|
||||
log.info(f'Created shared collection: {mt_collection_name}')
|
||||
log.info('Created shared collection: %s', mt_collection_name)
|
||||
|
||||
def _ensure_collection(self, mt_collection_name: str, dimension: int):
|
||||
if not self.client.has_collection(mt_collection_name):
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ class OpenGaussClient(VectorDBBase):
|
|||
new_items.append(new_chunk)
|
||||
self.session.bulk_save_objects(new_items)
|
||||
self.session.commit()
|
||||
log.info(f"Inserting {len(new_items)} items into collection '{collection_name}'.")
|
||||
log.info("Inserting %s items into collection '%s'.", len(new_items), collection_name)
|
||||
except Exception as e:
|
||||
self.session.rollback()
|
||||
log.exception(f'Failed to insert data: {e}')
|
||||
|
|
@ -207,7 +207,7 @@ class OpenGaussClient(VectorDBBase):
|
|||
)
|
||||
self.session.add(new_chunk)
|
||||
self.session.commit()
|
||||
log.info(f"Inserting/updating {len(items)} items in collection '{collection_name}'.")
|
||||
log.info("Inserting/updating %s items in collection '%s'.", len(items), collection_name)
|
||||
except Exception as e:
|
||||
self.session.rollback()
|
||||
log.exception(f'Failed to insert or update data.: {e}')
|
||||
|
|
@ -352,7 +352,7 @@ class OpenGaussClient(VectorDBBase):
|
|||
query = query.filter(DocumentChunk.vmetadata[key].astext == str(value))
|
||||
deleted = query.delete(synchronize_session=False)
|
||||
self.session.commit()
|
||||
log.info(f"Deleted {deleted} items from collection '{collection_name}'")
|
||||
log.info("Deleted %s items from collection '%s'", deleted, collection_name)
|
||||
except Exception as e:
|
||||
self.session.rollback()
|
||||
log.exception(f'Failed to delete data: {e}')
|
||||
|
|
@ -362,7 +362,7 @@ class OpenGaussClient(VectorDBBase):
|
|||
try:
|
||||
deleted = self.session.query(DocumentChunk).delete()
|
||||
self.session.commit()
|
||||
log.info(f'Reset completed. Deleted {deleted} items')
|
||||
log.info('Reset completed. Deleted %s items', deleted)
|
||||
except Exception as e:
|
||||
self.session.rollback()
|
||||
log.exception(f'Reset failed: {e}')
|
||||
|
|
@ -386,4 +386,4 @@ class OpenGaussClient(VectorDBBase):
|
|||
|
||||
def delete_collection(self, collection_name: str) -> None:
|
||||
self.delete(collection_name)
|
||||
log.info(f"Collection '{collection_name}' has been deleted")
|
||||
log.info("Collection '%s' has been deleted", collection_name)
|
||||
|
|
|
|||
|
|
@ -94,10 +94,10 @@ class Oracle23aiClient(VectorDBBase):
|
|||
self._create_dbcs_pool()
|
||||
|
||||
dsn = ORACLE_DB_DSN
|
||||
log.info(f'Creating Connection Pool [{ORACLE_DB_USER}:**@{dsn}]')
|
||||
log.info('Creating Connection Pool [%s:**@%s]', ORACLE_DB_USER, dsn)
|
||||
|
||||
with self.get_connection() as connection:
|
||||
log.info(f'Connection version: {connection.version}')
|
||||
log.info('Connection version: %s', connection.version)
|
||||
self._initialize_database(connection)
|
||||
|
||||
log.info('Oracle Vector Search initialization complete.')
|
||||
|
|
@ -159,7 +159,7 @@ class Oracle23aiClient(VectorDBBase):
|
|||
|
||||
if attempt < max_retries - 1:
|
||||
wait_time = 2**attempt
|
||||
log.info(f'Retrying in {wait_time} seconds...')
|
||||
log.info('Retrying in %s seconds...', wait_time)
|
||||
time.sleep(wait_time)
|
||||
else:
|
||||
raise
|
||||
|
|
@ -184,7 +184,7 @@ class Oracle23aiClient(VectorDBBase):
|
|||
|
||||
thread = threading.Thread(target=_monitor, daemon=True)
|
||||
thread.start()
|
||||
log.info(f'Started DB health monitor every {interval_seconds} seconds.')
|
||||
log.info('Started DB health monitor every %s seconds.', interval_seconds)
|
||||
|
||||
def _reconnect_pool(self):
|
||||
"""
|
||||
|
|
@ -412,7 +412,7 @@ class Oracle23aiClient(VectorDBBase):
|
|||
... ]
|
||||
>>> client.insert("my_collection", items)
|
||||
"""
|
||||
log.info(f"Inserting {len(items)} items into collection '{collection_name}'.")
|
||||
log.info("Inserting %s items into collection '%s'.", len(items), collection_name)
|
||||
|
||||
with self.get_connection() as connection:
|
||||
try:
|
||||
|
|
@ -437,7 +437,7 @@ class Oracle23aiClient(VectorDBBase):
|
|||
)
|
||||
|
||||
connection.commit()
|
||||
log.info(f"Successfully inserted {len(items)} items into collection '{collection_name}'.")
|
||||
log.info("Successfully inserted %s items into collection '%s'.", len(items), collection_name)
|
||||
|
||||
except Exception as e:
|
||||
connection.rollback()
|
||||
|
|
@ -466,7 +466,7 @@ class Oracle23aiClient(VectorDBBase):
|
|||
... ]
|
||||
>>> client.upsert("my_collection", items)
|
||||
"""
|
||||
log.info(f"Upserting {len(items)} items into collection '{collection_name}'.")
|
||||
log.info("Upserting %s items into collection '%s'.", len(items), collection_name)
|
||||
|
||||
with self.get_connection() as connection:
|
||||
try:
|
||||
|
|
@ -505,7 +505,7 @@ class Oracle23aiClient(VectorDBBase):
|
|||
)
|
||||
|
||||
connection.commit()
|
||||
log.info(f"Successfully upserted {len(items)} items into collection '{collection_name}'.")
|
||||
log.info("Successfully upserted %s items into collection '%s'.", len(items), collection_name)
|
||||
|
||||
except Exception as e:
|
||||
connection.rollback()
|
||||
|
|
@ -541,7 +541,7 @@ class Oracle23aiClient(VectorDBBase):
|
|||
... for i, (id, dist) in enumerate(zip(results.ids[0], results.distances[0])):
|
||||
... log.info(f"Match {i+1}: id={id}, distance={dist}")
|
||||
"""
|
||||
log.info(f"Searching items from collection '{collection_name}' with limit {limit}.")
|
||||
log.info("Searching items from collection '%s' with limit %s.", collection_name, limit)
|
||||
|
||||
try:
|
||||
if not vectors:
|
||||
|
|
@ -587,7 +587,7 @@ class Oracle23aiClient(VectorDBBase):
|
|||
metadatas[qid].append(self._json_to_metadata(metadata_str))
|
||||
distances[qid].append(float(row[3]))
|
||||
|
||||
log.info(f'Search completed. Found {sum(len(ids[i]) for i in range(num_queries))} total results.')
|
||||
log.info('Search completed. Found %s total results.', sum(len(ids[i]) for i in range(num_queries)))
|
||||
|
||||
return SearchResult(ids=ids, distances=distances, documents=documents, metadatas=metadatas)
|
||||
|
||||
|
|
@ -616,7 +616,7 @@ class Oracle23aiClient(VectorDBBase):
|
|||
>>> if results:
|
||||
... print(f"Found {len(results.ids[0])} matching documents")
|
||||
"""
|
||||
log.info(f"Querying items from collection '{collection_name}' with filters.")
|
||||
log.info("Querying items from collection '%s' with filters.", collection_name)
|
||||
|
||||
try:
|
||||
limit = limit or 100
|
||||
|
|
@ -656,7 +656,7 @@ class Oracle23aiClient(VectorDBBase):
|
|||
]
|
||||
]
|
||||
|
||||
log.info(f'Query completed. Found {len(results)} results.')
|
||||
log.info('Query completed. Found %s results.', len(results))
|
||||
|
||||
return GetResult(ids=ids, documents=documents, metadatas=metadatas)
|
||||
|
||||
|
|
@ -747,7 +747,7 @@ class Oracle23aiClient(VectorDBBase):
|
|||
>>> # Or delete by metadata filter
|
||||
>>> client.delete("my_collection", filter={"source": "deprecated_source"})
|
||||
"""
|
||||
log.info(f"Deleting items from collection '{collection_name}'.")
|
||||
log.info("Deleting items from collection '%s'.", collection_name)
|
||||
|
||||
try:
|
||||
query = 'DELETE FROM document_chunk WHERE collection_name = :collection_name'
|
||||
|
|
@ -772,7 +772,7 @@ class Oracle23aiClient(VectorDBBase):
|
|||
deleted = cursor.rowcount
|
||||
connection.commit()
|
||||
|
||||
log.info(f"Deleted {deleted} items from collection '{collection_name}'.")
|
||||
log.info("Deleted %s items from collection '%s'.", deleted, collection_name)
|
||||
|
||||
except Exception as e:
|
||||
log.exception(f'Error during delete: {e}')
|
||||
|
|
@ -800,7 +800,7 @@ class Oracle23aiClient(VectorDBBase):
|
|||
deleted = cursor.rowcount
|
||||
connection.commit()
|
||||
|
||||
log.info(f"Reset complete. Deleted {deleted} items from 'document_chunk' table.")
|
||||
log.info("Reset complete. Deleted %s items from 'document_chunk' table.", deleted)
|
||||
|
||||
except Exception as e:
|
||||
log.exception(f'Error during reset: {e}')
|
||||
|
|
@ -875,7 +875,7 @@ class Oracle23aiClient(VectorDBBase):
|
|||
>>> client = Oracle23aiClient()
|
||||
>>> client.delete_collection("obsolete_collection")
|
||||
"""
|
||||
log.info(f"Deleting collection '{collection_name}'.")
|
||||
log.info("Deleting collection '%s'.", collection_name)
|
||||
|
||||
try:
|
||||
with self.get_connection() as connection:
|
||||
|
|
@ -891,7 +891,7 @@ class Oracle23aiClient(VectorDBBase):
|
|||
deleted = cursor.rowcount
|
||||
connection.commit()
|
||||
|
||||
log.info(f"Collection '{collection_name}' deleted. Removed {deleted} items.")
|
||||
log.info("Collection '%s' deleted. Removed %s items.", collection_name, deleted)
|
||||
|
||||
except Exception as e:
|
||||
log.exception(f"Error deleting collection '{collection_name}': {e}")
|
||||
|
|
|
|||
|
|
@ -326,7 +326,7 @@ class PgvectorClient(VectorDBBase):
|
|||
},
|
||||
)
|
||||
self.session.commit()
|
||||
log.info(f"Encrypted & inserted {len(items)} into '{collection_name}'")
|
||||
log.info("Encrypted & inserted %s into '%s'", len(items), collection_name)
|
||||
|
||||
else:
|
||||
new_items = []
|
||||
|
|
@ -342,7 +342,7 @@ class PgvectorClient(VectorDBBase):
|
|||
new_items.append(new_chunk)
|
||||
self.session.bulk_save_objects(new_items)
|
||||
self.session.commit()
|
||||
log.info(f"Inserted {len(new_items)} items into collection '{collection_name}'.")
|
||||
log.info("Inserted %s items into collection '%s'.", len(new_items), collection_name)
|
||||
except Exception as e:
|
||||
self.session.rollback()
|
||||
log.exception(f'Error during insert: {e}')
|
||||
|
|
@ -381,7 +381,7 @@ class PgvectorClient(VectorDBBase):
|
|||
},
|
||||
)
|
||||
self.session.commit()
|
||||
log.info(f"Encrypted & upserted {len(items)} into '{collection_name}'")
|
||||
log.info("Encrypted & upserted %s into '%s'", len(items), collection_name)
|
||||
else:
|
||||
for item in items:
|
||||
vector = self.adjust_vector_length(item['vector'])
|
||||
|
|
@ -401,7 +401,7 @@ class PgvectorClient(VectorDBBase):
|
|||
)
|
||||
self.session.add(new_chunk)
|
||||
self.session.commit()
|
||||
log.info(f"Upserted {len(items)} items into collection '{collection_name}'.")
|
||||
log.info("Upserted %s items into collection '%s'.", len(items), collection_name)
|
||||
except Exception as e:
|
||||
self.session.rollback()
|
||||
log.exception(f'Error during upsert: {e}')
|
||||
|
|
@ -712,7 +712,7 @@ class PgvectorClient(VectorDBBase):
|
|||
query = query.filter(DocumentChunk.vmetadata[key].astext == str(value))
|
||||
deleted = query.delete(synchronize_session=False)
|
||||
self.session.commit()
|
||||
log.info(f"Deleted {deleted} items from collection '{collection_name}'.")
|
||||
log.info("Deleted %s items from collection '%s'.", deleted, collection_name)
|
||||
except Exception as e:
|
||||
self.session.rollback()
|
||||
log.exception(f'Error during delete: {e}')
|
||||
|
|
@ -722,7 +722,7 @@ class PgvectorClient(VectorDBBase):
|
|||
try:
|
||||
deleted = self.session.query(DocumentChunk).delete()
|
||||
self.session.commit()
|
||||
log.info(f"Reset complete. Deleted {deleted} items from 'document_chunk' table.")
|
||||
log.info("Reset complete. Deleted %s items from 'document_chunk' table.", deleted)
|
||||
except Exception as e:
|
||||
self.session.rollback()
|
||||
log.exception(f'Error during reset: {e}')
|
||||
|
|
@ -746,4 +746,4 @@ class PgvectorClient(VectorDBBase):
|
|||
|
||||
def delete_collection(self, collection_name: str) -> None:
|
||||
self.delete(collection_name)
|
||||
log.info(f"Collection '{collection_name}' deleted.")
|
||||
log.info("Collection '%s' deleted.", collection_name)
|
||||
|
|
|
|||
|
|
@ -106,16 +106,16 @@ class PineconeClient(VectorDBBase):
|
|||
try:
|
||||
# Check if index exists
|
||||
if self.index_name not in self.client.list_indexes().names():
|
||||
log.info(f"Creating Pinecone index '{self.index_name}'...")
|
||||
log.info("Creating Pinecone index '%s'...", self.index_name)
|
||||
self.client.create_index(
|
||||
name=self.index_name,
|
||||
dimension=self.dimension,
|
||||
metric=self.metric,
|
||||
spec=ServerlessSpec(cloud=self.cloud, region=self.environment),
|
||||
)
|
||||
log.info(f"Successfully created Pinecone index '{self.index_name}'")
|
||||
log.info("Successfully created Pinecone index '%s'", self.index_name)
|
||||
else:
|
||||
log.info(f"Using existing Pinecone index '{self.index_name}'")
|
||||
log.info("Using existing Pinecone index '%s'", self.index_name)
|
||||
|
||||
# Connect to the index
|
||||
self.index = self.client.Index(
|
||||
|
|
@ -245,7 +245,7 @@ class PineconeClient(VectorDBBase):
|
|||
collection_name_with_prefix = self._get_collection_name_with_prefix(collection_name)
|
||||
try:
|
||||
self.index.delete(filter={'collection_name': collection_name_with_prefix})
|
||||
log.info(f"Collection '{collection_name_with_prefix}' deleted (all vectors removed).")
|
||||
log.info("Collection '%s' deleted (all vectors removed).", collection_name_with_prefix)
|
||||
except Exception as e:
|
||||
log.warning(f"Failed to delete collection '{collection_name_with_prefix}': {e}")
|
||||
raise
|
||||
|
|
@ -276,7 +276,7 @@ class PineconeClient(VectorDBBase):
|
|||
elapsed = time.time() - start_time
|
||||
log.debug('Insert of %s vectors took %.2f seconds', len(points), elapsed)
|
||||
log.info(
|
||||
f"Successfully inserted {len(points)} vectors in parallel batches into '{collection_name_with_prefix}'"
|
||||
"Successfully inserted %s vectors in parallel batches into '%s'", len(points), collection_name_with_prefix
|
||||
)
|
||||
|
||||
def upsert(self, collection_name: str, items: List[VectorItem]) -> None:
|
||||
|
|
@ -305,7 +305,7 @@ class PineconeClient(VectorDBBase):
|
|||
elapsed = time.time() - start_time
|
||||
log.debug('Upsert of %s vectors took %.2f seconds', len(points), elapsed)
|
||||
log.info(
|
||||
f"Successfully upserted {len(points)} vectors in parallel batches into '{collection_name_with_prefix}'"
|
||||
"Successfully upserted %s vectors in parallel batches into '%s'", len(points), collection_name_with_prefix
|
||||
)
|
||||
|
||||
async def insert_async(self, collection_name: str, items: List[VectorItem]) -> None:
|
||||
|
|
@ -326,7 +326,9 @@ class PineconeClient(VectorDBBase):
|
|||
if isinstance(result, Exception):
|
||||
log.error(f'Error in async insert batch: {result}')
|
||||
raise result
|
||||
log.info(f"Successfully async inserted {len(points)} vectors in batches into '{collection_name_with_prefix}'")
|
||||
log.info(
|
||||
"Successfully async inserted %s vectors in batches into '%s'", len(points), collection_name_with_prefix
|
||||
)
|
||||
|
||||
async def upsert_async(self, collection_name: str, items: List[VectorItem]) -> None:
|
||||
"""Async version of upsert using asyncio and run_in_executor for improved performance."""
|
||||
|
|
@ -346,7 +348,9 @@ class PineconeClient(VectorDBBase):
|
|||
if isinstance(result, Exception):
|
||||
log.error(f'Error in async upsert batch: {result}')
|
||||
raise result
|
||||
log.info(f"Successfully async upserted {len(points)} vectors in batches into '{collection_name_with_prefix}'")
|
||||
log.info(
|
||||
"Successfully async upserted %s vectors in batches into '%s'", len(points), collection_name_with_prefix
|
||||
)
|
||||
|
||||
def search(
|
||||
self,
|
||||
|
|
@ -477,7 +481,7 @@ class PineconeClient(VectorDBBase):
|
|||
log.debug(
|
||||
"Deleted batch of %s vectors by ID from '%s'", len(batch_ids), collection_name_with_prefix
|
||||
)
|
||||
log.info(f"Successfully deleted {len(ids)} vectors by ID from '{collection_name_with_prefix}'")
|
||||
log.info("Successfully deleted %s vectors by ID from '%s'", len(ids), collection_name_with_prefix)
|
||||
|
||||
elif filter:
|
||||
# Combine user filter with collection_name
|
||||
|
|
@ -486,7 +490,7 @@ class PineconeClient(VectorDBBase):
|
|||
pinecone_filter.update(filter)
|
||||
# Delete by metadata filter
|
||||
self.index.delete(filter=pinecone_filter)
|
||||
log.info(f"Successfully deleted vectors by filter from '{collection_name_with_prefix}'")
|
||||
log.info("Successfully deleted vectors by filter from '%s'", collection_name_with_prefix)
|
||||
|
||||
else:
|
||||
log.warning('No ids or filter provided for delete operation')
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ class QdrantClient(VectorDBBase):
|
|||
on_disk=self.QDRANT_ON_DISK,
|
||||
),
|
||||
)
|
||||
log.info(f'collection {collection_name_with_prefix} successfully created!')
|
||||
log.info('collection %s successfully created!', collection_name_with_prefix)
|
||||
|
||||
def _create_collection_if_not_exists(self, collection_name, dimension):
|
||||
if not self.has_collection(collection_name=collection_name):
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ class QdrantClient(VectorDBBase):
|
|||
m=0,
|
||||
),
|
||||
)
|
||||
log.info(f'Multi-tenant collection {mt_collection_name} created with dimension {dimension}!')
|
||||
log.info('Multi-tenant collection %s created with dimension %s!', mt_collection_name, dimension)
|
||||
|
||||
self.client.create_payload_index(
|
||||
collection_name=mt_collection_name,
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class S3VectorClient(VectorDBBase):
|
|||
if self.bucket_name and self.region:
|
||||
try:
|
||||
self.client = boto3.client('s3vectors', region_name=self.region)
|
||||
log.info(f"S3Vector client initialized for bucket '{self.bucket_name}' in region '{self.region}'")
|
||||
log.info("S3Vector client initialized for bucket '%s' in region '%s'", self.bucket_name, self.region)
|
||||
except Exception as e:
|
||||
log.error(f'Failed to initialize S3Vector client: {e}')
|
||||
self.client = None
|
||||
|
|
@ -70,7 +70,9 @@ class S3VectorClient(VectorDBBase):
|
|||
]
|
||||
},
|
||||
)
|
||||
log.info(f'Created S3 index: {index_name} (dim={dimension}, type={data_type}, metric={distance_metric})')
|
||||
log.info(
|
||||
'Created S3 index: %s (dim=%s, type=%s, metric=%s)', index_name, dimension, data_type, distance_metric
|
||||
)
|
||||
except Exception as e:
|
||||
log.error(f"Error creating S3 index '{index_name}': {e}")
|
||||
raise
|
||||
|
|
@ -137,9 +139,9 @@ class S3VectorClient(VectorDBBase):
|
|||
return
|
||||
|
||||
try:
|
||||
log.info(f"Deleting collection '{collection_name}'")
|
||||
log.info("Deleting collection '%s'", collection_name)
|
||||
self.client.delete_index(vectorBucketName=self.bucket_name, indexName=collection_name)
|
||||
log.info(f"Successfully deleted collection '{collection_name}'")
|
||||
log.info("Successfully deleted collection '%s'", collection_name)
|
||||
except Exception as e:
|
||||
log.error(f"Error deleting collection '{collection_name}': {e}")
|
||||
raise
|
||||
|
|
@ -156,7 +158,7 @@ class S3VectorClient(VectorDBBase):
|
|||
|
||||
try:
|
||||
if not self.has_collection(collection_name):
|
||||
log.info(f"Index '{collection_name}' does not exist. Creating index.")
|
||||
log.info("Index '%s' does not exist. Creating index.", collection_name)
|
||||
self._create_index(
|
||||
index_name=collection_name,
|
||||
dimension=dimension,
|
||||
|
|
@ -202,9 +204,11 @@ class S3VectorClient(VectorDBBase):
|
|||
indexName=collection_name,
|
||||
vectors=batch,
|
||||
)
|
||||
log.info(f"Inserted batch {i // batch_size + 1}: {len(batch)} vectors into index '{collection_name}'.")
|
||||
log.info(
|
||||
"Inserted batch %s: %s vectors into index '%s'.", i // batch_size + 1, len(batch), collection_name
|
||||
)
|
||||
|
||||
log.info(f"Completed insertion of {len(vectors)} vectors into index '{collection_name}'.")
|
||||
log.info("Completed insertion of %s vectors into index '%s'.", len(vectors), collection_name)
|
||||
except Exception as e:
|
||||
log.error(f'Error inserting vectors: {e}')
|
||||
raise
|
||||
|
|
@ -218,11 +222,11 @@ class S3VectorClient(VectorDBBase):
|
|||
return
|
||||
|
||||
dimension = len(items[0]['vector'])
|
||||
log.info(f'Upsert dimension: {dimension}')
|
||||
log.info('Upsert dimension: %s', dimension)
|
||||
|
||||
try:
|
||||
if not self.has_collection(collection_name):
|
||||
log.info(f"Index '{collection_name}' does not exist. Creating index for upsert.")
|
||||
log.info("Index '%s' does not exist. Creating index for upsert.", collection_name)
|
||||
self._create_index(
|
||||
index_name=collection_name,
|
||||
dimension=dimension,
|
||||
|
|
@ -264,10 +268,14 @@ class S3VectorClient(VectorDBBase):
|
|||
batch = vectors[i : i + batch_size]
|
||||
if i == 0: # Log sample info for first batch only
|
||||
log.info(
|
||||
f'Upserting batch 1: {len(batch)} vectors. First vector sample: key={batch[0]["key"]}, data_type={type(batch[0]["data"]["float32"])}, data_len={len(batch[0]["data"]["float32"])}'
|
||||
'Upserting batch 1: %s vectors. First vector sample: key=%s, data_type=%s, data_len=%s',
|
||||
len(batch),
|
||||
batch[0]['key'],
|
||||
type(batch[0]['data']['float32']),
|
||||
len(batch[0]['data']['float32']),
|
||||
)
|
||||
else:
|
||||
log.info(f'Upserting batch {i // batch_size + 1}: {len(batch)} vectors.')
|
||||
log.info('Upserting batch %s: %s vectors.', i // batch_size + 1, len(batch))
|
||||
|
||||
self.client.put_vectors(
|
||||
vectorBucketName=self.bucket_name,
|
||||
|
|
@ -275,7 +283,7 @@ class S3VectorClient(VectorDBBase):
|
|||
vectors=batch,
|
||||
)
|
||||
|
||||
log.info(f"Completed upsert of {len(vectors)} vectors into index '{collection_name}'.")
|
||||
log.info("Completed upsert of %s vectors into index '%s'.", len(vectors), collection_name)
|
||||
except Exception as e:
|
||||
log.error(f'Error upserting vectors: {e}')
|
||||
raise
|
||||
|
|
@ -300,7 +308,7 @@ class S3VectorClient(VectorDBBase):
|
|||
return None
|
||||
|
||||
try:
|
||||
log.info(f"Searching collection '{collection_name}' with {len(vectors)} query vectors, limit={limit}")
|
||||
log.info("Searching collection '%s' with %s query vectors, limit=%s", collection_name, len(vectors), limit)
|
||||
|
||||
# Initialize result lists
|
||||
all_ids = []
|
||||
|
|
@ -362,7 +370,7 @@ class S3VectorClient(VectorDBBase):
|
|||
all_metadatas.append(query_metadatas)
|
||||
all_distances.append(query_distances)
|
||||
|
||||
log.info(f'Search completed. Found results for {len(all_ids)} queries')
|
||||
log.info('Search completed. Found results for %s queries', len(all_ids))
|
||||
|
||||
# Return SearchResult format
|
||||
return SearchResult(
|
||||
|
|
@ -402,7 +410,7 @@ class S3VectorClient(VectorDBBase):
|
|||
return self.get(collection_name)
|
||||
|
||||
try:
|
||||
log.info(f"Querying collection '{collection_name}' with filter: {filter}")
|
||||
log.info("Querying collection '%s' with filter: %s", collection_name, filter)
|
||||
|
||||
# For S3 Vector, we need to use list_vectors and then filter results
|
||||
# Since S3 Vector may not support complex server-side filtering,
|
||||
|
|
@ -437,7 +445,7 @@ class S3VectorClient(VectorDBBase):
|
|||
if limit and len(filtered_ids) >= limit:
|
||||
break
|
||||
|
||||
log.info(f'Filter applied: {len(filtered_ids)} vectors match out of {len(all_ids)} total')
|
||||
log.info('Filter applied: %s vectors match out of %s total', len(filtered_ids), len(all_ids))
|
||||
|
||||
# Return GetResult format
|
||||
if filtered_ids:
|
||||
|
|
@ -472,7 +480,7 @@ class S3VectorClient(VectorDBBase):
|
|||
return GetResult(ids=[[]], documents=[[]], metadatas=[[]])
|
||||
|
||||
try:
|
||||
log.info(f"Retrieving all vectors from collection '{collection_name}'")
|
||||
log.info("Retrieving all vectors from collection '%s'", collection_name)
|
||||
|
||||
# Initialize result lists
|
||||
all_ids = []
|
||||
|
|
@ -534,7 +542,7 @@ class S3VectorClient(VectorDBBase):
|
|||
if not next_token:
|
||||
break
|
||||
|
||||
log.info(f"Retrieved {len(all_ids)} vectors from collection '{collection_name}'")
|
||||
log.info("Retrieved %s vectors from collection '%s'", len(all_ids), collection_name)
|
||||
|
||||
# Return in GetResult format
|
||||
# The Open WebUI GetResult expects lists of lists, so we wrap each list
|
||||
|
|
@ -576,17 +584,17 @@ class S3VectorClient(VectorDBBase):
|
|||
try:
|
||||
if ids:
|
||||
# Delete by specific vector IDs/keys
|
||||
log.info(f"Deleting {len(ids)} vectors by IDs from collection '{collection_name}'")
|
||||
log.info("Deleting %s vectors by IDs from collection '%s'", len(ids), collection_name)
|
||||
self.client.delete_vectors(
|
||||
vectorBucketName=self.bucket_name,
|
||||
indexName=collection_name,
|
||||
keys=ids,
|
||||
)
|
||||
log.info(f"Deleted {len(ids)} vectors from index '{collection_name}'")
|
||||
log.info("Deleted %s vectors from index '%s'", len(ids), collection_name)
|
||||
|
||||
elif filter:
|
||||
# Handle filter-based deletion
|
||||
log.info(f"Deleting vectors by filter from collection '{collection_name}': {filter}")
|
||||
log.info("Deleting vectors by filter from collection '%s': %s", collection_name, filter)
|
||||
|
||||
# If this is a knowledge collection and we have a file_id filter,
|
||||
# also clean up the corresponding file-specific collection
|
||||
|
|
@ -595,7 +603,8 @@ class S3VectorClient(VectorDBBase):
|
|||
file_collection_name = f'file-{file_id}'
|
||||
if self.has_collection(file_collection_name):
|
||||
log.info(
|
||||
f"Found related file-specific collection '{file_collection_name}', deleting it to prevent duplicates"
|
||||
"Found related file-specific collection '%s', deleting it to prevent duplicates",
|
||||
file_collection_name,
|
||||
)
|
||||
self.delete_collection(file_collection_name)
|
||||
|
||||
|
|
@ -604,7 +613,7 @@ class S3VectorClient(VectorDBBase):
|
|||
query_result = self.query(collection_name, filter)
|
||||
if query_result and query_result.ids and query_result.ids[0]:
|
||||
matching_ids = query_result.ids[0]
|
||||
log.info(f'Found {len(matching_ids)} vectors matching filter, deleting them')
|
||||
log.info('Found %s vectors matching filter, deleting them', len(matching_ids))
|
||||
|
||||
# Delete the matching vectors by ID
|
||||
self.client.delete_vectors(
|
||||
|
|
@ -612,7 +621,7 @@ class S3VectorClient(VectorDBBase):
|
|||
indexName=collection_name,
|
||||
keys=matching_ids,
|
||||
)
|
||||
log.info(f"Deleted {len(matching_ids)} vectors from index '{collection_name}' using filter")
|
||||
log.info("Deleted %s vectors from index '%s' using filter", len(matching_ids), collection_name)
|
||||
else:
|
||||
log.warning('No vectors found matching the filter criteria')
|
||||
else:
|
||||
|
|
@ -645,11 +654,11 @@ class S3VectorClient(VectorDBBase):
|
|||
try:
|
||||
self.client.delete_index(vectorBucketName=self.bucket_name, indexName=index_name)
|
||||
deleted_count += 1
|
||||
log.info(f'Deleted index: {index_name}')
|
||||
log.info('Deleted index: %s', index_name)
|
||||
except Exception as e:
|
||||
log.error(f"Error deleting index '{index_name}': {e}")
|
||||
|
||||
log.info(f'Reset completed: deleted {deleted_count} indexes')
|
||||
log.info('Reset completed: deleted %s indexes', deleted_count)
|
||||
|
||||
except Exception as e:
|
||||
log.error(f'Error during reset: {e}')
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ class ValkeyClient(VectorDBBase):
|
|||
f'{self._format_version(MIN_VALKEY_VERSION)}. valkey-search 1.2.0 requires Valkey core '
|
||||
'9.0.1 or later. Upgrade your server or use valkey-bundle:9.1.0-rc2+.'
|
||||
)
|
||||
log.info(f'Valkey core version: {self._format_version(version) if version else "unknown"}')
|
||||
log.info('Valkey core version: %s', self._format_version(version) if version else 'unknown')
|
||||
|
||||
def _check_search_module(self) -> None:
|
||||
try:
|
||||
|
|
@ -331,7 +331,7 @@ class ValkeyClient(VectorDBBase):
|
|||
'TEXT field type and filter-only FT.SEARCH support required by this backend. '
|
||||
'Upgrade to valkey-bundle:9.1.0-rc2+ or load valkey-search 1.2.0+ as a module.'
|
||||
)
|
||||
log.info(f'valkey-search version: {self._format_version(search_version) if search_version else "unknown"}')
|
||||
log.info('valkey-search version: %s', self._format_version(search_version) if search_version else 'unknown')
|
||||
|
||||
def _index_name(self, collection_name: str) -> str:
|
||||
return f'idx:{self.collection_prefix}:{collection_name}'
|
||||
|
|
@ -385,8 +385,11 @@ class ValkeyClient(VectorDBBase):
|
|||
try:
|
||||
g['glide_ft'].create(self.client, index_name, schema, options)
|
||||
log.info(
|
||||
f'Created Valkey index {index_name} with dimension={dimension}, '
|
||||
f'type={self.index_type}, metric={self.distance_metric}'
|
||||
'Created Valkey index %s with dimension=%s, type=%s, metric=%s',
|
||||
index_name,
|
||||
dimension,
|
||||
self.index_type,
|
||||
self.distance_metric,
|
||||
)
|
||||
except g['RequestError'] as e:
|
||||
if 'already exists' in str(e).lower():
|
||||
|
|
@ -456,7 +459,7 @@ class ValkeyClient(VectorDBBase):
|
|||
index_name = self._index_name(collection_name)
|
||||
try:
|
||||
self._g['glide_ft'].dropindex(self.client, index_name)
|
||||
log.info(f'Dropped index {index_name}')
|
||||
log.info('Dropped index %s', index_name)
|
||||
except self._g['RequestError'] as e:
|
||||
log.debug('Could not drop index %s: %s', index_name, e)
|
||||
|
||||
|
|
@ -656,7 +659,7 @@ class ValkeyClient(VectorDBBase):
|
|||
collections.append(name[len(idx_prefix) :])
|
||||
try:
|
||||
glide_ft.dropindex(self.client, idx)
|
||||
log.info(f'Dropped index: {name}')
|
||||
log.info('Dropped index: %s', name)
|
||||
except Exception as e:
|
||||
log.error(f'Error dropping index {name}: {e}')
|
||||
except Exception as e:
|
||||
|
|
@ -664,7 +667,7 @@ class ValkeyClient(VectorDBBase):
|
|||
|
||||
for collection in collections:
|
||||
self._delete_keys_by_prefix(self._key_prefix(collection))
|
||||
log.info(f'Valkey vector store reset complete (prefix: {self.collection_prefix})')
|
||||
log.info('Valkey vector store reset complete (prefix: %s)', self.collection_prefix)
|
||||
|
||||
def _delete_keys_by_prefix(self, prefix: str) -> None:
|
||||
cursor = '0'
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ def search_exa(
|
|||
count (int): Number of results to return
|
||||
filter_list (Optional[list[str]]): List of domains to filter results by
|
||||
"""
|
||||
log.info(f'Searching with Exa for query: {query}')
|
||||
log.info('Searching with Exa for query: %s', query)
|
||||
|
||||
headers = {'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json'}
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ def search_exa(
|
|||
)
|
||||
)
|
||||
|
||||
log.info(f'Found {len(results)} results')
|
||||
log.info('Found %s results', len(results))
|
||||
return [
|
||||
SearchResult(
|
||||
link=result.url,
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ def search_external(
|
|||
)
|
||||
for result in results[:count]
|
||||
]
|
||||
log.info(f'External search results: {results}')
|
||||
log.info('External search results: %s', results)
|
||||
return results
|
||||
except Exception as e:
|
||||
log.error(f'Error in External search: {e}')
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ def search_firecrawl(
|
|||
)
|
||||
)
|
||||
|
||||
log.info(f'FireCrawl search results: {search_results}')
|
||||
log.info('FireCrawl search results: %s', search_results)
|
||||
return search_results
|
||||
except Exception as e:
|
||||
log.error(f'Error in FireCrawl search: {e}')
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ def search_ollama_cloud(
|
|||
count (int): Number of results to return
|
||||
filter_list (Optional[list[str]]): List of domains to filter results by
|
||||
"""
|
||||
log.info(f'Searching with Ollama for query: {query}')
|
||||
log.info('Searching with Ollama for query: %s', query)
|
||||
|
||||
headers = {'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json'}
|
||||
payload = {'query': query, 'max_results': count}
|
||||
|
|
@ -34,7 +34,7 @@ def search_ollama_cloud(
|
|||
data = response.json()
|
||||
|
||||
results = data.get('results', [])
|
||||
log.info(f'Found {len(results)} results')
|
||||
log.info('Found %s results', len(results))
|
||||
|
||||
if filter_list:
|
||||
results = get_filtered_results(results, filter_list)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ def search_searchapi(
|
|||
response = requests.request('GET', url)
|
||||
|
||||
json_response = response.json()
|
||||
log.info(f'results from searchapi search: {json_response}')
|
||||
log.info('results from searchapi search: %s', json_response)
|
||||
|
||||
results = sorted(json_response.get('organic_results', []), key=lambda x: x.get('position', 0))
|
||||
if filter_list:
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ def search_serpapi(
|
|||
response = requests.request('GET', url)
|
||||
|
||||
json_response = response.json()
|
||||
log.info(f'results from serpapi search: {json_response}')
|
||||
log.info('results from serpapi search: %s', json_response)
|
||||
|
||||
results = sorted(json_response.get('organic_results', []), key=lambda x: x.get('position', 0))
|
||||
if filter_list:
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ def search_serply(
|
|||
response.raise_for_status()
|
||||
|
||||
json_response = response.json()
|
||||
log.info(f'results from serply search: {json_response}')
|
||||
log.info('results from serply search: %s', json_response)
|
||||
|
||||
results = sorted(json_response.get('results', []), key=lambda x: x.get('realPosition', 0))
|
||||
if filter_list:
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ def search_yandex(
|
|||
for result in results[:count]
|
||||
]
|
||||
|
||||
log.info(f'Yandex search results: {results}')
|
||||
log.info('Yandex search results: %s', results)
|
||||
|
||||
return results
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ def convert_audio_to_mp3(file_path):
|
|||
output_path = os.path.splitext(file_path)[0] + '.mp3'
|
||||
audio = AudioSegment.from_file(file_path)
|
||||
audio.export(output_path, format='mp3')
|
||||
log.info(f'Converted {file_path} to {output_path}')
|
||||
log.info('Converted %s to %s', file_path, output_path)
|
||||
return output_path
|
||||
except Exception as e:
|
||||
log.error(f'Error converting audio file: {e}')
|
||||
|
|
@ -208,7 +208,7 @@ def transcode_audio_to_mp3(audio_data: bytes, content_type_header: str, output_p
|
|||
audio_segment = AudioSegment.from_file(io.BytesIO(audio_data))
|
||||
|
||||
audio_segment.export(str(output_path), format='mp3')
|
||||
log.info(f'Transcoded {mime_type} audio to MP3: {output_path}')
|
||||
log.info('Transcoded %s audio to MP3: %s', mime_type, output_path)
|
||||
return True
|
||||
|
||||
|
||||
|
|
@ -631,7 +631,7 @@ async def _transcribe_whisper(request, file_path, languages, file_dir, id):
|
|||
language=languages[0],
|
||||
multilingual=WHISPER_MULTILINGUAL,
|
||||
)
|
||||
log.info("Detected language '%s' with probability %f" % (info.language, info.language_probability))
|
||||
log.info("Detected language '%s' with probability %f", info.language, info.language_probability)
|
||||
return ''.join([segment.text for segment in list(segments)])
|
||||
|
||||
transcript = await asyncio.to_thread(_run)
|
||||
|
|
@ -952,7 +952,9 @@ async def _transcribe_mistral(request, file_path, filename, metadata, file_dir,
|
|||
try:
|
||||
model = await Config.get('audio.stt.model') or 'voxtral-mini-latest'
|
||||
log.info(
|
||||
f'Mistral STT - model: {model}, method: {"chat_completions" if use_chat_completions else "transcriptions"}'
|
||||
'Mistral STT - model: %s, method: %s',
|
||||
model,
|
||||
'chat_completions' if use_chat_completions else 'transcriptions',
|
||||
)
|
||||
|
||||
session = await get_session()
|
||||
|
|
@ -1075,7 +1077,7 @@ async def _transcribe_mistral(request, file_path, filename, metadata, file_dir,
|
|||
|
||||
|
||||
async def transcribe(request: Request, file_path: str, metadata: Optional[dict] = None, user=None):
|
||||
log.info(f'transcribe: {file_path} {metadata}')
|
||||
log.info('transcribe: %s %s', file_path, metadata)
|
||||
|
||||
if BYPASS_PYDUB_PREPROCESSING:
|
||||
log.info('Bypassing pydub preprocessing (BYPASS_PYDUB_PREPROCESSING=true)')
|
||||
|
|
@ -1202,7 +1204,7 @@ async def transcription(
|
|||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
|
||||
)
|
||||
log.info(f'file.content_type: {file.content_type}')
|
||||
log.info('file.content_type: %s', file.content_type)
|
||||
stt_supported_content_types = await Config.get('audio.stt.supported_content_types', [])
|
||||
|
||||
if not strict_match_mime_type(stt_supported_content_types, file.content_type):
|
||||
|
|
|
|||
|
|
@ -548,8 +548,8 @@ async def ldap_auth(
|
|||
]
|
||||
if ENABLE_LDAP_GROUP_MANAGEMENT:
|
||||
search_attributes.append(f'{LDAP_ATTRIBUTE_FOR_GROUPS}')
|
||||
log.info(f'LDAP Group Management enabled. Adding {LDAP_ATTRIBUTE_FOR_GROUPS} to search attributes')
|
||||
log.info(f'LDAP search attributes: {search_attributes}')
|
||||
log.info('LDAP Group Management enabled. Adding %s to search attributes', LDAP_ATTRIBUTE_FOR_GROUPS)
|
||||
log.info('LDAP search attributes: %s', search_attributes)
|
||||
|
||||
search_success = await asyncio.to_thread(
|
||||
connection_app.search,
|
||||
|
|
@ -586,30 +586,30 @@ async def ldap_auth(
|
|||
user_groups = []
|
||||
if ENABLE_LDAP_GROUP_MANAGEMENT and LDAP_ATTRIBUTE_FOR_GROUPS in entry:
|
||||
group_dns = entry[LDAP_ATTRIBUTE_FOR_GROUPS]
|
||||
log.info(f'LDAP raw group DNs for user {username_list}: {group_dns}')
|
||||
log.info('LDAP raw group DNs for user %s: %s', username_list, group_dns)
|
||||
|
||||
if group_dns:
|
||||
log.info(f'LDAP group_dns original: {group_dns}')
|
||||
log.info(f'LDAP group_dns type: {type(group_dns)}')
|
||||
log.info(f'LDAP group_dns length: {len(group_dns)}')
|
||||
log.info('LDAP group_dns original: %s', group_dns)
|
||||
log.info('LDAP group_dns type: %s', type(group_dns))
|
||||
log.info('LDAP group_dns length: %s', len(group_dns))
|
||||
|
||||
if hasattr(group_dns, 'value'):
|
||||
group_dns = group_dns.value
|
||||
log.info(f'Extracted .value property: {group_dns}')
|
||||
log.info('Extracted .value property: %s', group_dns)
|
||||
elif hasattr(group_dns, '__iter__') and not isinstance(group_dns, (str, bytes)):
|
||||
group_dns = list(group_dns)
|
||||
log.info(f'Converted to list: {group_dns}')
|
||||
log.info('Converted to list: %s', group_dns)
|
||||
|
||||
if isinstance(group_dns, list):
|
||||
group_dns = [str(item) for item in group_dns]
|
||||
else:
|
||||
group_dns = [str(group_dns)]
|
||||
|
||||
log.info(f'LDAP group_dns after processing - type: {type(group_dns)}, length: {len(group_dns)}')
|
||||
log.info('LDAP group_dns after processing - type: %s, length: %s', type(group_dns), len(group_dns))
|
||||
|
||||
for group_idx, group_dn in enumerate(group_dns):
|
||||
group_dn = str(group_dn)
|
||||
log.info(f'Processing group DN #{group_idx + 1}: {group_dn}')
|
||||
log.info('Processing group DN #%s: %s', group_idx + 1, group_dn)
|
||||
|
||||
try:
|
||||
group_cn = extract_group_cn_from_dn(group_dn)
|
||||
|
|
@ -621,9 +621,9 @@ async def ldap_auth(
|
|||
except Exception as e:
|
||||
log.warning(f'Failed to extract group name from DN {group_dn}: {e}')
|
||||
|
||||
log.info(f'LDAP groups for user {username_list}: {user_groups} (total: {len(user_groups)})')
|
||||
log.info('LDAP groups for user %s: %s (total: %s)', username_list, user_groups, len(user_groups))
|
||||
else:
|
||||
log.info(f'No groups found for user {username_list}')
|
||||
log.info('No groups found for user %s', username_list)
|
||||
elif ENABLE_LDAP_GROUP_MANAGEMENT:
|
||||
log.warning(
|
||||
f'LDAP Group Management enabled but {LDAP_ATTRIBUTE_FOR_GROUPS} attribute not found in user entry'
|
||||
|
|
@ -691,7 +691,7 @@ async def ldap_auth(
|
|||
if ENABLE_LDAP_GROUP_CREATION:
|
||||
await Groups.create_groups_by_group_names(user.id, user_groups, db=db)
|
||||
await Groups.sync_groups_by_group_names(user.id, user_groups, db=db)
|
||||
log.info(f'Successfully synced groups for user {user.id}: {user_groups}')
|
||||
log.info('Successfully synced groups for user %s: %s', user.id, user_groups)
|
||||
except Exception as e:
|
||||
log.error(f'Failed to sync groups for user {user.id}: {e}')
|
||||
|
||||
|
|
@ -1156,7 +1156,7 @@ async def get_admin_details(
|
|||
admin_email = await Config.get('auth.admin.email')
|
||||
admin_name = None
|
||||
|
||||
log.info(f'Admin details - Email: {admin_email}, Name: {admin_name}')
|
||||
log.info('Admin details - Email: %s, Name: %s', admin_email, admin_name)
|
||||
|
||||
if admin_email:
|
||||
admin = await Users.get_user_by_email(admin_email, db=db)
|
||||
|
|
|
|||
|
|
@ -575,7 +575,7 @@ async def verify_tool_servers_config(request: Request, form_data: ToolServerConn
|
|||
'oauth_server_metadata': oauth_server_metadata.model_dump(mode='json'),
|
||||
}
|
||||
except Exception as e:
|
||||
log.info(f'Failed to parse OAuth 2.1 discovery document: {e}')
|
||||
log.info('Failed to parse OAuth 2.1 discovery document: %s', e)
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f'Failed to parse OAuth 2.1 discovery document from {discovery_url}',
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ async def process_uploaded_file(
|
|||
# processing (Tools, vision models). Attempting text
|
||||
# extraction causes "Timeout reached while detecting
|
||||
# encoding" errors.
|
||||
log.info(f'Video file detected ({content_type}), skipping text extraction')
|
||||
log.info('Video file detected (%s), skipping text extraction', content_type)
|
||||
await Files.update_file_data_by_id(
|
||||
file_item.id,
|
||||
{'status': 'completed'},
|
||||
|
|
@ -190,7 +190,7 @@ async def process_uploaded_file(
|
|||
# Documents, or media files explicitly enabled for the
|
||||
# configured content extraction engine.
|
||||
if not content_type:
|
||||
log.info(f'File type {file.content_type} is not provided, but trying to process anyway')
|
||||
log.info('File type %s is not provided, but trying to process anyway', file.content_type)
|
||||
await process_file(
|
||||
request,
|
||||
ProcessFileForm(file_id=file_item.id),
|
||||
|
|
@ -242,7 +242,7 @@ async def process_uploaded_file(
|
|||
)
|
||||
if not knowledge_file:
|
||||
raise Exception(f'Failed to link file {file_item.id} to knowledge {knowledge_id}')
|
||||
log.info(f'Linked file {file_item.id} to knowledge {knowledge_id}')
|
||||
log.info('Linked file %s to knowledge %s', file_item.id, knowledge_id)
|
||||
except Exception as e:
|
||||
log.warning(f'Failed to link file {file_item.id} to knowledge {knowledge_id}: {e}')
|
||||
raise
|
||||
|
|
@ -322,7 +322,7 @@ async def upload_file_handler(
|
|||
background_tasks: Optional[BackgroundTasks] = None,
|
||||
db: Optional[AsyncSession] = None,
|
||||
):
|
||||
log.info(f'file.content_type: {file.content_type} {process}')
|
||||
log.info('file.content_type: %s %s', file.content_type, process)
|
||||
|
||||
if isinstance(metadata, str):
|
||||
try:
|
||||
|
|
@ -868,7 +868,7 @@ async def get_html_file_content_by_id(
|
|||
|
||||
# Check if the file already exists in the cache
|
||||
if file_path.is_file():
|
||||
log.info(f'file_path: {file_path}')
|
||||
log.info('file_path: %s', file_path)
|
||||
return FileResponse(file_path)
|
||||
else:
|
||||
raise HTTPException(
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ def get_image_file_item(base64_string, param_name='image'):
|
|||
|
||||
|
||||
async def set_image_model(request: Request, model: str):
|
||||
log.info(f'Setting image model to {model}')
|
||||
log.info('Setting image model to %s', model)
|
||||
await Config.upsert({'image_generation.model': model})
|
||||
image_config = await get_image_config()
|
||||
if image_config.IMAGE_GENERATION_ENGINE in ['', 'automatic1111']:
|
||||
|
|
|
|||
|
|
@ -351,7 +351,7 @@ async def reindex_knowledge_files(
|
|||
failed_files = []
|
||||
start_time = time.monotonic()
|
||||
|
||||
log.info(f'Starting reindexing for {len(knowledge_bases)} knowledge bases ({total_files} files)')
|
||||
log.info('Starting reindexing for %s knowledge bases (%s files)', len(knowledge_bases), total_files)
|
||||
|
||||
for kb_idx, (knowledge_base, files) in enumerate(knowledge_base_files, start=1):
|
||||
try:
|
||||
|
|
@ -371,8 +371,13 @@ async def reindex_knowledge_files(
|
|||
eta = f', ETA: {round(elapsed / (processed_files - 1) * remaining_files)}s'
|
||||
|
||||
log.info(
|
||||
f'Reindexing knowledge base {kb_idx}/{len(knowledge_bases)} '
|
||||
f'file {processed_files}/{total_files}{eta}: {file.filename}'
|
||||
'Reindexing knowledge base %s/%s file %s/%s%s: %s',
|
||||
kb_idx,
|
||||
len(knowledge_bases),
|
||||
processed_files,
|
||||
total_files,
|
||||
eta,
|
||||
file.filename,
|
||||
)
|
||||
|
||||
try:
|
||||
|
|
@ -397,7 +402,7 @@ async def reindex_knowledge_files(
|
|||
for failed in failed_files:
|
||||
log.warning(f'File ID: {failed["file_id"]}, Error: {failed["error"]}')
|
||||
|
||||
log.info(f'Reindexing completed in {round(time.monotonic() - start_time)}s.')
|
||||
log.info('Reindexing completed in %ss.', round(time.monotonic() - start_time))
|
||||
await publish_event(
|
||||
request,
|
||||
EVENTS.KNOWLEDGE_REINDEXED,
|
||||
|
|
@ -426,14 +431,14 @@ async def reindex_knowledge_base_metadata_embeddings(
|
|||
this entire operation would exhaust the connection pool.
|
||||
"""
|
||||
knowledge_bases = await Knowledges.get_knowledge_bases()
|
||||
log.info(f'Reindexing embeddings for {len(knowledge_bases)} knowledge bases')
|
||||
log.info('Reindexing embeddings for %s knowledge bases', len(knowledge_bases))
|
||||
|
||||
success_count = 0
|
||||
for kb in knowledge_bases:
|
||||
if await embed_knowledge_base_metadata(request, kb.id, kb.name, kb.description):
|
||||
success_count += 1
|
||||
|
||||
log.info(f'Embedding reindex complete: {success_count}/{len(knowledge_bases)}')
|
||||
log.info('Embedding reindex complete: %s/%s', success_count, len(knowledge_bases))
|
||||
return {'total': len(knowledge_bases), 'success': success_count}
|
||||
|
||||
|
||||
|
|
@ -1687,11 +1692,11 @@ async def delete_knowledge_by_id(
|
|||
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
|
||||
)
|
||||
|
||||
log.info(f'Deleting knowledge base: {id} (name: {knowledge.name})')
|
||||
log.info('Deleting knowledge base: %s (name: %s)', id, knowledge.name)
|
||||
|
||||
# Get all models
|
||||
models = await Models.get_all_models(db=db)
|
||||
log.info(f'Found {len(models)} models to check for knowledge base {id}')
|
||||
log.info('Found %s models to check for knowledge base %s', len(models), id)
|
||||
|
||||
# Update models that reference this knowledge base
|
||||
for model in models:
|
||||
|
|
@ -1702,7 +1707,7 @@ async def delete_knowledge_by_id(
|
|||
|
||||
# If the knowledge list changed, update the model
|
||||
if len(updated_knowledge) != len(knowledge_list):
|
||||
log.info(f'Updating model {model.id} to remove knowledge base {id}')
|
||||
log.info('Updating model %s to remove knowledge base %s', model.id, id)
|
||||
model.meta.knowledge = updated_knowledge
|
||||
model_form = ModelForm(**model.model_dump())
|
||||
await Models.update_model_by_id(model.id, model_form, db=db)
|
||||
|
|
@ -2022,7 +2027,7 @@ async def add_files_to_knowledge_batch(
|
|||
)
|
||||
|
||||
# Batch-fetch all files to avoid N+1 queries
|
||||
log.info(f'files/batch/add - {len(form_data)} files')
|
||||
log.info('files/batch/add - %s files', len(form_data))
|
||||
file_ids = [form.file_id for form in form_data]
|
||||
files = await Files.get_files_by_ids(file_ids, db=db)
|
||||
|
||||
|
|
|
|||
|
|
@ -650,7 +650,7 @@ async def pull_model(
|
|||
form_data['model'] = form_data.get('model', form_data.get('name'))
|
||||
|
||||
url = (await Config.get('ollama.base_urls', []))[url_idx]
|
||||
log.info(f'url: {url}')
|
||||
log.info('url: %s', url)
|
||||
|
||||
# Admins may pull from any registry
|
||||
return await send_request(
|
||||
|
|
@ -881,7 +881,7 @@ async def embed(
|
|||
if not await Config.get('ollama.enable'):
|
||||
raise HTTPException(status_code=503, detail=ERROR_MESSAGES.OLLAMA_API_DISABLED)
|
||||
|
||||
log.info(f'generate_ollama_batch_embeddings {form_data}')
|
||||
log.info('generate_ollama_batch_embeddings %s', form_data)
|
||||
await check_model_access(user, await Models.get_model_by_id(form_data.model), BYPASS_MODEL_ACCESS_CONTROL)
|
||||
await validate_ollama_backend_idx(request, form_data.model, url_idx, user)
|
||||
|
||||
|
|
@ -932,7 +932,7 @@ async def embeddings(
|
|||
if not await Config.get('ollama.enable'):
|
||||
raise HTTPException(status_code=503, detail=ERROR_MESSAGES.OLLAMA_API_DISABLED)
|
||||
|
||||
log.info(f'generate_ollama_embeddings {form_data}')
|
||||
log.info('generate_ollama_embeddings %s', form_data)
|
||||
await check_model_access(user, await Models.get_model_by_id(form_data.model), BYPASS_MODEL_ACCESS_CONTROL)
|
||||
await validate_ollama_backend_idx(request, form_data.model, url_idx, user)
|
||||
|
||||
|
|
@ -1637,11 +1637,11 @@ async def upload_model(
|
|||
async def file_process_stream():
|
||||
nonlocal ollama_url
|
||||
total_size = os.path.getsize(file_path)
|
||||
log.info(f'Total Model Size: {total_size}')
|
||||
log.info('Total Model Size: %s', total_size)
|
||||
|
||||
# Stage 2: hash the file and emit SSE progress
|
||||
file_hash = await asyncio.to_thread(calculate_sha256, file_path, chunk_size)
|
||||
log.info(f'Model Hash: {file_hash}')
|
||||
log.info('Model Hash: %s', file_hash)
|
||||
|
||||
try:
|
||||
bytes_read = 0
|
||||
|
|
@ -1675,13 +1675,13 @@ async def upload_model(
|
|||
|
||||
# Stage 4: create the model
|
||||
model, _ext = os.path.splitext(filename)
|
||||
log.info(f'Created Model: {model}')
|
||||
log.info('Created Model: %s', model)
|
||||
|
||||
create_payload = {
|
||||
'model': model,
|
||||
'files': {filename: f'sha256:{file_hash}'},
|
||||
}
|
||||
log.info(f'Model Payload: {create_payload}')
|
||||
log.info('Model Payload: %s', create_payload)
|
||||
|
||||
async with session.post(
|
||||
f'{ollama_url}/api/create',
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ async def upload_pipeline(
|
|||
file: UploadFile = File(...),
|
||||
user=Depends(get_admin_user),
|
||||
):
|
||||
log.info(f'upload_pipeline: urlIdx={urlIdx}, filename={file.filename}')
|
||||
log.info('upload_pipeline: urlIdx=%s, filename=%s', urlIdx, file.filename)
|
||||
filename = os.path.basename(file.filename)
|
||||
|
||||
# Check if the uploaded file is a python file
|
||||
|
|
|
|||
|
|
@ -519,7 +519,7 @@ async def unload_embedding_model(request: Request):
|
|||
@router.post('/embedding/update')
|
||||
async def update_embedding_config(request: Request, form_data: EmbeddingModelUpdateForm, user=Depends(get_admin_user)):
|
||||
config = await get_retrieval_config()
|
||||
log.info(f'Updating embedding model: {config.RAG_EMBEDDING_MODEL} to {form_data.RAG_EMBEDDING_MODEL}')
|
||||
log.info('Updating embedding model: %s to %s', config.RAG_EMBEDDING_MODEL, form_data.RAG_EMBEDDING_MODEL)
|
||||
await unload_embedding_model(request)
|
||||
try:
|
||||
config.RAG_EMBEDDING_ENGINE = form_data.RAG_EMBEDDING_ENGINE
|
||||
|
|
@ -1159,7 +1159,7 @@ async def update_rag_config(request: Request, form_data: ConfigForm, user=Depend
|
|||
else config.RAG_RERANKING_BATCH_SIZE
|
||||
)
|
||||
|
||||
log.info(f'Updating reranking model: {config.RAG_RERANKING_MODEL} to {form_data.RAG_RERANKING_MODEL}')
|
||||
log.info('Updating reranking model: %s to %s', config.RAG_RERANKING_MODEL, form_data.RAG_RERANKING_MODEL)
|
||||
try:
|
||||
config.RAG_RERANKING_MODEL = (
|
||||
form_data.RAG_RERANKING_MODEL if form_data.RAG_RERANKING_MODEL is not None else config.RAG_RERANKING_MODEL
|
||||
|
|
@ -1663,7 +1663,7 @@ def save_docs_to_vector_db(
|
|||
existing_file_id = result.metadatas[0][0].get('file_id')
|
||||
|
||||
if existing_file_id != metadata.get('file_id'):
|
||||
log.info(f'Document with hash {metadata["hash"]} already exists')
|
||||
log.info('Document with hash %s already exists', metadata['hash'])
|
||||
raise ValueError(ERROR_MESSAGES.DUPLICATE_CONTENT)
|
||||
|
||||
if split:
|
||||
|
|
@ -1706,7 +1706,7 @@ def save_docs_to_vector_db(
|
|||
)
|
||||
docs = text_splitter.split_documents(docs)
|
||||
elif config.TEXT_SPLITTER == 'token':
|
||||
log.info(f'Using token text splitter: {config.TIKTOKEN_ENCODING_NAME}')
|
||||
log.info('Using token text splitter: %s', config.TIKTOKEN_ENCODING_NAME)
|
||||
|
||||
tiktoken.get_encoding(str(config.TIKTOKEN_ENCODING_NAME))
|
||||
text_splitter = TokenTextSplitter(
|
||||
|
|
@ -1748,16 +1748,16 @@ def save_docs_to_vector_db(
|
|||
|
||||
try:
|
||||
if VECTOR_DB_CLIENT.has_collection(collection_name=collection_name):
|
||||
log.info(f'collection {collection_name} already exists')
|
||||
log.info('collection %s already exists', collection_name)
|
||||
|
||||
if overwrite:
|
||||
VECTOR_DB_CLIENT.delete_collection(collection_name=collection_name)
|
||||
log.info(f'deleting existing collection {collection_name}')
|
||||
log.info('deleting existing collection %s', collection_name)
|
||||
elif add is False:
|
||||
log.info(f'collection {collection_name} already exists, overwrite is False and add is False')
|
||||
log.info('collection %s already exists, overwrite is False and add is False', collection_name)
|
||||
return True
|
||||
|
||||
log.info(f'generating embeddings for {collection_name}')
|
||||
log.info('generating embeddings for %s', collection_name)
|
||||
embedding_function = get_embedding_function(
|
||||
config.RAG_EMBEDDING_ENGINE,
|
||||
config.RAG_EMBEDDING_MODEL,
|
||||
|
|
@ -1801,7 +1801,7 @@ def save_docs_to_vector_db(
|
|||
request.app.state.main_loop,
|
||||
)
|
||||
embeddings = future.result(timeout=embedding_timeout)
|
||||
log.info(f'embeddings generated {len(embeddings)} for {len(texts)} items')
|
||||
log.info('embeddings generated %s for %s items', len(embeddings), len(texts))
|
||||
|
||||
items = [
|
||||
{
|
||||
|
|
@ -1813,13 +1813,13 @@ def save_docs_to_vector_db(
|
|||
for idx, text in enumerate(texts)
|
||||
]
|
||||
|
||||
log.info(f'adding to collection {collection_name}')
|
||||
log.info('adding to collection %s', collection_name)
|
||||
VECTOR_DB_CLIENT.insert(
|
||||
collection_name=collection_name,
|
||||
items=items,
|
||||
)
|
||||
|
||||
log.info(f'added {len(items)} items to collection {collection_name}')
|
||||
log.info('added %s items to collection %s', len(items), collection_name)
|
||||
return True
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
|
|
@ -2011,7 +2011,7 @@ async def process_file(
|
|||
add=(True if form_data.collection_name else False),
|
||||
user=user,
|
||||
)
|
||||
log.info(f'added {len(docs)} items to collection {collection_name}')
|
||||
log.info('added %s items to collection %s', len(docs), collection_name)
|
||||
|
||||
if result:
|
||||
# Fresh session for the final update.
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@ def get_scim_auth(request: Request, authorization: Optional[str] = Header(None))
|
|||
|
||||
# Check if SCIM is enabled
|
||||
enable_scim = getattr(request.app.state, 'ENABLE_SCIM', False)
|
||||
log.info(f'SCIM auth check - raw ENABLE_SCIM: {enable_scim}, type: {type(enable_scim)}')
|
||||
log.info('SCIM auth check - raw ENABLE_SCIM: %s, type: %s', enable_scim, type(enable_scim))
|
||||
|
||||
if not enable_scim:
|
||||
raise HTTPException(
|
||||
|
|
|
|||
|
|
@ -412,7 +412,7 @@ async def generate_queries(request: Request, form_data: dict, user=Depends(get_v
|
|||
)
|
||||
|
||||
if getattr(request.state, 'cached_queries', None):
|
||||
log.info(f'Reusing cached queries: {request.state.cached_queries}')
|
||||
log.info('Reusing cached queries: %s', request.state.cached_queries)
|
||||
return request.state.cached_queries
|
||||
|
||||
if getattr(request.state, 'direct', False) and hasattr(request.state, 'model'):
|
||||
|
|
|
|||
|
|
@ -331,7 +331,7 @@ async def disconnect_user_sessions(user_id: str):
|
|||
for sid in session_ids:
|
||||
await sio.disconnect(sid)
|
||||
if session_ids:
|
||||
log.info(f'Disconnected {len(session_ids)} session(s) for user {user_id}')
|
||||
log.info('Disconnected %s session(s) for user %s', len(session_ids), user_id)
|
||||
except Exception as e:
|
||||
log.warning(f'Failed to disconnect sessions for user {user_id}: {e}')
|
||||
|
||||
|
|
@ -626,7 +626,7 @@ async def ydoc_document_join(sid, data):
|
|||
user_name = data.get('user_name', 'Anonymous')
|
||||
user_color = data.get('user_color', '#000000')
|
||||
|
||||
log.info(f'User {user_id} joining document {document_id}')
|
||||
log.info('User %s joining document %s', user_id, document_id)
|
||||
await YDOC_MANAGER.add_user(document_id=document_id, user_id=sid)
|
||||
|
||||
# Join Socket.IO room
|
||||
|
|
@ -665,7 +665,7 @@ async def ydoc_document_join(sid, data):
|
|||
skip_sid=sid,
|
||||
)
|
||||
|
||||
log.info(f'User {user_id} successfully joined document {document_id}')
|
||||
log.info('User %s successfully joined document %s', user_id, document_id)
|
||||
|
||||
except Exception as e:
|
||||
log.error(f'Error in yjs_document_join: {e}')
|
||||
|
|
@ -826,7 +826,7 @@ async def yjs_document_leave(sid, data):
|
|||
try:
|
||||
document_id = normalize_document_id(data['document_id'])
|
||||
|
||||
log.info(f'User {user["id"]} leaving document {document_id}')
|
||||
log.info('User %s leaving document %s', user['id'], document_id)
|
||||
|
||||
# Remove user from the document
|
||||
await YDOC_MANAGER.remove_user(document_id=document_id, user_id=sid)
|
||||
|
|
@ -842,7 +842,7 @@ async def yjs_document_leave(sid, data):
|
|||
)
|
||||
|
||||
if await YDOC_MANAGER.document_exists(document_id) and len(await YDOC_MANAGER.get_users(document_id)) == 0:
|
||||
log.info(f'Cleaning up document {document_id} as no users are left')
|
||||
log.info('Cleaning up document %s as no users are left', document_id)
|
||||
await YDOC_MANAGER.clear_document(document_id)
|
||||
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -542,7 +542,7 @@ async def create_admin_user(email: str, password: str, name: str = 'Admin'):
|
|||
log.debug('Users already exist, skipping admin creation')
|
||||
return None
|
||||
|
||||
log.info(f'Creating admin account from environment variables: {email}')
|
||||
log.info('Creating admin account from environment variables: %s', email)
|
||||
try:
|
||||
hashed = await get_password_hash(password)
|
||||
user = await Auths.insert_new_auth(
|
||||
|
|
@ -552,7 +552,7 @@ async def create_admin_user(email: str, password: str, name: str = 'Admin'):
|
|||
role='admin',
|
||||
)
|
||||
if user:
|
||||
log.info(f'Admin account created successfully: {email}')
|
||||
log.info('Admin account created successfully: %s', email)
|
||||
return user
|
||||
else:
|
||||
log.error('Failed to create admin account from environment variables')
|
||||
|
|
|
|||
|
|
@ -211,8 +211,9 @@ async def scheduler_worker_loop(app) -> None:
|
|||
SCHEDULER_POLL_INTERVAL env var (default: 10 seconds).
|
||||
"""
|
||||
log.info(
|
||||
f'Scheduler worker started (timer poll interval: {TIMER_POLL_INTERVAL}s, '
|
||||
f'scheduler poll interval: {SCHEDULER_POLL_INTERVAL}s)'
|
||||
'Scheduler worker started (timer poll interval: %ss, scheduler poll interval: %ss)',
|
||||
TIMER_POLL_INTERVAL,
|
||||
SCHEDULER_POLL_INTERVAL,
|
||||
)
|
||||
next_scheduler_poll = 0.0
|
||||
|
||||
|
|
@ -240,7 +241,7 @@ async def scheduler_worker_loop(app) -> None:
|
|||
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)')
|
||||
log.info('Claimed %s due automation(s)', len(batch))
|
||||
for automation in batch:
|
||||
asyncio.create_task(execute_automation(app, automation))
|
||||
except Exception:
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ async def generate_direct_chat_completion(
|
|||
)
|
||||
|
||||
channel = f'{user_id}:{session_id}:{request_id}'
|
||||
logging.info(f'WebSocket channel: {channel}')
|
||||
logging.info('WebSocket channel: %s', channel)
|
||||
|
||||
if form_data.get('stream'):
|
||||
q = asyncio.Queue()
|
||||
|
|
@ -95,7 +95,7 @@ async def generate_direct_chat_completion(
|
|||
}
|
||||
)
|
||||
|
||||
log.info(f'res: {res}')
|
||||
log.info('res: %s', res)
|
||||
|
||||
if res.get('status', False):
|
||||
# Define a generator to stream responses
|
||||
|
|
|
|||
|
|
@ -1193,7 +1193,7 @@ def stream_chunks_handler(stream: aiohttp.StreamReader):
|
|||
if len(line) > max_buffer_size:
|
||||
skip_mode = True
|
||||
yield b'data: {}\n'
|
||||
log.info(f'Skip mode triggered, line size: {len(line)}')
|
||||
log.info('Skip mode triggered, line size: %s', len(line))
|
||||
else:
|
||||
yield line + b'\n'
|
||||
|
||||
|
|
@ -1203,7 +1203,7 @@ def stream_chunks_handler(stream: aiohttp.StreamReader):
|
|||
# Check if buffer exceeds limit
|
||||
if not skip_mode and len(buffer) > max_buffer_size:
|
||||
skip_mode = True
|
||||
log.info(f'Skip mode triggered, buffer size: {len(buffer)}')
|
||||
log.info('Skip mode triggered, buffer size: %s', len(buffer))
|
||||
# Clear oversized buffer to prevent unlimited growth
|
||||
buffer = b''
|
||||
|
||||
|
|
|
|||
|
|
@ -377,13 +377,13 @@ async def get_all_models(request, refresh: bool = False, user: UserModel = None)
|
|||
if items is None:
|
||||
action_function = functions_by_id.get(action_id)
|
||||
if action_function is None:
|
||||
log.info(f'Action not found: {action_id}')
|
||||
log.info('Action not found: %s', action_id)
|
||||
action_items_by_id[action_id] = []
|
||||
continue
|
||||
|
||||
function_module = functions_cache.get(action_id)
|
||||
if function_module is None:
|
||||
log.info(f'Failed to load action module: {action_id}')
|
||||
log.info('Failed to load action module: %s', action_id)
|
||||
action_items_by_id[action_id] = []
|
||||
continue
|
||||
items = get_action_items_from_module(action_function, function_module)
|
||||
|
|
@ -397,13 +397,13 @@ async def get_all_models(request, refresh: bool = False, user: UserModel = None)
|
|||
if items is None:
|
||||
filter_function = functions_by_id.get(filter_id)
|
||||
if filter_function is None:
|
||||
log.info(f'Filter not found: {filter_id}')
|
||||
log.info('Filter not found: %s', filter_id)
|
||||
filter_items_by_id[filter_id] = []
|
||||
continue
|
||||
|
||||
function_module = functions_cache.get(filter_id)
|
||||
if function_module is None:
|
||||
log.info(f'Failed to load filter module: {filter_id}')
|
||||
log.info('Failed to load filter module: %s', filter_id)
|
||||
filter_items_by_id[filter_id] = []
|
||||
continue
|
||||
if getattr(function_module, 'toggle', None):
|
||||
|
|
|
|||
|
|
@ -608,7 +608,9 @@ async def get_oauth_client_info_with_dynamic_client_registration(
|
|||
}
|
||||
)
|
||||
log.info(
|
||||
f'Dynamic client registration successful at {registration_url}, client_id: {oauth_client_info.client_id}'
|
||||
'Dynamic client registration successful at %s, client_id: %s',
|
||||
registration_url,
|
||||
oauth_client_info.client_id,
|
||||
)
|
||||
return oauth_client_info
|
||||
except Exception as e:
|
||||
|
|
@ -701,7 +703,7 @@ async def get_oauth_client_info_with_static_credentials(
|
|||
)
|
||||
|
||||
log.info(
|
||||
f'Static OAuth client info built for {oauth_client_id} using metadata from {oauth_server_metadata_url}'
|
||||
'Static OAuth client info built for %s using metadata from %s', oauth_client_id, oauth_server_metadata_url
|
||||
)
|
||||
return oauth_client_info
|
||||
except Exception as e:
|
||||
|
|
@ -807,7 +809,7 @@ async def recover_static_oauth_client_metadata(connection: dict, oauth_client_in
|
|||
recovered = {**oauth_client_info}
|
||||
if not recovered.get('scope') and resource_metadata.scopes_supported:
|
||||
recovered['scope'] = ' '.join(resource_metadata.scopes_supported)
|
||||
log.info(f'Recovered static OAuth scopes for {server_url} from protected resource metadata')
|
||||
log.info('Recovered static OAuth scopes for %s from protected resource metadata', server_url)
|
||||
|
||||
if not recovered.get('resource') and resource_metadata.resource:
|
||||
recovered['resource'] = resource_metadata.resource
|
||||
|
|
@ -916,7 +918,7 @@ class OAuthClientManager:
|
|||
def remove_client(self, client_id):
|
||||
if client_id in self.clients:
|
||||
del self.clients[client_id]
|
||||
log.info(f'Removed OAuth client {client_id}')
|
||||
log.info('Removed OAuth client %s', client_id)
|
||||
|
||||
if hasattr(self.oauth, '_clients'):
|
||||
if client_id in self.oauth._clients:
|
||||
|
|
@ -1074,7 +1076,7 @@ class OAuthClientManager:
|
|||
if refreshed_token:
|
||||
# Update the session with new token data
|
||||
session = await OAuthSessions.update_session_by_id(session.id, refreshed_token)
|
||||
log.info(f'Successfully refreshed token for session {session.id}')
|
||||
log.info('Successfully refreshed token for session %s', session.id)
|
||||
return session.token
|
||||
else:
|
||||
log.error(f'Failed to refresh token for session {session.id}')
|
||||
|
|
@ -1242,7 +1244,7 @@ class OAuthClientManager:
|
|||
provider=client_id,
|
||||
token=token,
|
||||
)
|
||||
log.info(f'Stored OAuth session server-side for user {user_id}, client_id {client_id}')
|
||||
log.info('Stored OAuth session server-side for user %s, client_id %s', user_id, client_id)
|
||||
except Exception as e:
|
||||
error_message = 'Failed to store OAuth session server-side'
|
||||
log.error(f'Failed to store OAuth session server-side: {e}')
|
||||
|
|
@ -1369,7 +1371,7 @@ class OAuthManager:
|
|||
if refreshed_token:
|
||||
# Update the session with new token data
|
||||
session = await OAuthSessions.update_session_by_id(session.id, refreshed_token)
|
||||
log.info(f'Successfully refreshed token for session {session.id}')
|
||||
log.info('Successfully refreshed token for session %s', session.id)
|
||||
return session.token
|
||||
else:
|
||||
log.error(f'Failed to refresh token for session {session.id}')
|
||||
|
|
@ -1594,7 +1596,7 @@ class OAuthManager:
|
|||
|
||||
for group_name in user_oauth_groups:
|
||||
if group_name not in all_group_names:
|
||||
log.info(f"Group '{group_name}' not found via OAuth claim. Creating group...")
|
||||
log.info("Group '%s' not found via OAuth claim. Creating group...", group_name)
|
||||
try:
|
||||
new_group_form = GroupForm(
|
||||
name=group_name,
|
||||
|
|
@ -1606,7 +1608,10 @@ class OAuthManager:
|
|||
created_group = await Groups.insert_new_group(creator_id, new_group_form, db=db)
|
||||
if created_group:
|
||||
log.info(
|
||||
f"Successfully created group '{group_name}' with ID {created_group.id} using creator ID {creator_id}"
|
||||
"Successfully created group '%s' with ID %s using creator ID %s",
|
||||
group_name,
|
||||
created_group.id,
|
||||
creator_id,
|
||||
)
|
||||
groups_created = True
|
||||
# Add to local set to prevent duplicate creation attempts in this run
|
||||
|
|
@ -2096,7 +2101,7 @@ class OAuthManager:
|
|||
**({'max_age': cookie_max_age} if cookie_max_age is not None else {}),
|
||||
)
|
||||
|
||||
log.info(f'Stored OAuth session server-side for user {user.id}, provider {provider}')
|
||||
log.info('Stored OAuth session server-side for user %s, provider %s', user.id, provider)
|
||||
else:
|
||||
log.warning(f'Failed to create OAuth session for user {user.id}, provider {provider}')
|
||||
except Exception as e:
|
||||
|
|
@ -2280,11 +2285,14 @@ class OAuthManager:
|
|||
revoked_count += 1
|
||||
|
||||
log.info(
|
||||
f'Back-channel logout: revoked sessions for user {user.id} '
|
||||
f'(email={user.email}, provider={matched_provider}, sessions_deleted={len(sessions)})'
|
||||
'Back-channel logout: revoked sessions for user %s (email=%s, provider=%s, sessions_deleted=%s)',
|
||||
user.id,
|
||||
user.email,
|
||||
matched_provider,
|
||||
len(sessions),
|
||||
)
|
||||
|
||||
log.info(
|
||||
f'Back-channel logout: completed for {len(users_to_logout)} user(s), {revoked_count} revocation(s) set'
|
||||
'Back-channel logout: completed for %s user(s), %s revocation(s) set', len(users_to_logout), revoked_count
|
||||
)
|
||||
return JSONResponse(status_code=200, content={})
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ async def load_tool_module_by_id(tool_id, content=None):
|
|||
exec(content, module.__dict__)
|
||||
if frontmatter is None:
|
||||
frontmatter = extract_frontmatter(content)
|
||||
log.info(f'Loaded module: {module.__name__}')
|
||||
log.info('Loaded module: %s', module.__name__)
|
||||
|
||||
# Create and return the object if the class 'Tools' is found in the module
|
||||
if hasattr(module, 'Tools'):
|
||||
|
|
@ -291,7 +291,7 @@ async def load_function_module_by_id(function_id: str, content: str | None = Non
|
|||
exec(content, module.__dict__)
|
||||
if frontmatter is None:
|
||||
frontmatter = extract_frontmatter(content)
|
||||
log.info(f'Loaded module: {module.__name__}')
|
||||
log.info('Loaded module: %s', module.__name__)
|
||||
|
||||
# Create appropriate object based on available class type in the module
|
||||
if hasattr(module, 'Pipe'):
|
||||
|
|
@ -437,7 +437,7 @@ def install_frontmatter_requirements(requirements: str):
|
|||
if not new_reqs:
|
||||
return
|
||||
|
||||
log.info(f'Installing requirements: {" ".join(new_reqs)}')
|
||||
log.info('Installing requirements: %s', ' '.join(new_reqs))
|
||||
subprocess.check_call(
|
||||
[sys.executable, '-m', 'pip', 'install'] + PIP_OPTIONS + new_reqs + PIP_PACKAGE_INDEX_OPTIONS
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue