local-deep-research 0.2.3__py3-none-any.whl → 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- local_deep_research/__init__.py +1 -1
- local_deep_research/advanced_search_system/filters/cross_engine_filter.py +5 -1
- local_deep_research/advanced_search_system/strategies/base_strategy.py +5 -2
- local_deep_research/advanced_search_system/strategies/iterdrag_strategy.py +23 -16
- local_deep_research/advanced_search_system/strategies/parallel_search_strategy.py +13 -6
- local_deep_research/advanced_search_system/strategies/rapid_search_strategy.py +4 -3
- local_deep_research/advanced_search_system/strategies/source_based_strategy.py +57 -62
- local_deep_research/advanced_search_system/strategies/standard_strategy.py +8 -4
- local_deep_research/api/research_functions.py +0 -46
- local_deep_research/citation_handler.py +2 -5
- local_deep_research/config/llm_config.py +25 -68
- local_deep_research/config/search_config.py +8 -21
- local_deep_research/defaults/default_settings.json +3814 -0
- local_deep_research/search_system.py +34 -31
- local_deep_research/utilities/db_utils.py +22 -3
- local_deep_research/utilities/search_utilities.py +10 -7
- local_deep_research/web/app.py +3 -23
- local_deep_research/web/app_factory.py +1 -25
- local_deep_research/web/database/migrations.py +20 -418
- local_deep_research/web/routes/settings_routes.py +75 -364
- local_deep_research/web/services/research_service.py +43 -43
- local_deep_research/web/services/settings_manager.py +108 -315
- local_deep_research/web/services/settings_service.py +3 -56
- local_deep_research/web/static/js/components/research.js +1 -1
- local_deep_research/web/static/js/components/settings.js +16 -4
- local_deep_research/web/static/js/research_form.js +106 -0
- local_deep_research/web/templates/pages/research.html +3 -2
- local_deep_research/web_search_engines/engines/meta_search_engine.py +13 -18
- local_deep_research/web_search_engines/engines/search_engine_local.py +11 -2
- local_deep_research/web_search_engines/engines/search_engine_local_all.py +7 -11
- local_deep_research/web_search_engines/search_engine_factory.py +12 -64
- local_deep_research/web_search_engines/search_engines_config.py +123 -64
- {local_deep_research-0.2.3.dist-info → local_deep_research-0.3.0.dist-info}/METADATA +16 -1
- {local_deep_research-0.2.3.dist-info → local_deep_research-0.3.0.dist-info}/RECORD +37 -39
- local_deep_research/config/config_files.py +0 -245
- local_deep_research/defaults/local_collections.toml +0 -53
- local_deep_research/defaults/main.toml +0 -80
- local_deep_research/defaults/search_engines.toml +0 -291
- {local_deep_research-0.2.3.dist-info → local_deep_research-0.3.0.dist-info}/WHEEL +0 -0
- {local_deep_research-0.2.3.dist-info → local_deep_research-0.3.0.dist-info}/entry_points.txt +0 -0
- {local_deep_research-0.2.3.dist-info → local_deep_research-0.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,15 +1,14 @@
|
|
1
|
+
import importlib.resources as pkg_resources
|
2
|
+
import json
|
1
3
|
import logging
|
2
4
|
import os
|
3
|
-
from pathlib import Path
|
4
5
|
from typing import Any, Dict, Optional, Union
|
5
6
|
|
6
|
-
import toml
|
7
7
|
from sqlalchemy import func
|
8
8
|
from sqlalchemy.exc import SQLAlchemyError
|
9
9
|
from sqlalchemy.orm import Session
|
10
10
|
|
11
|
-
from ...
|
12
|
-
from ...config.config_files import settings as dynaconf_settings
|
11
|
+
from ... import defaults
|
13
12
|
from ..database.models import Setting, SettingType
|
14
13
|
from ..models.settings import (
|
15
14
|
AppSetting,
|
@@ -23,6 +22,25 @@ from ..models.settings import (
|
|
23
22
|
logger = logging.getLogger(__name__)
|
24
23
|
|
25
24
|
|
25
|
+
def check_env_setting(key: str) -> str | None:
|
26
|
+
"""
|
27
|
+
Checks environment variables for a particular setting.
|
28
|
+
|
29
|
+
Args:
|
30
|
+
key: The database key for the setting.
|
31
|
+
|
32
|
+
Returns:
|
33
|
+
The setting from the environment variables, or None if the variable
|
34
|
+
is not set.
|
35
|
+
|
36
|
+
"""
|
37
|
+
env_variable_name = f"LDR_{"_".join(key.split(".")).upper()}"
|
38
|
+
env_value = os.getenv(env_variable_name)
|
39
|
+
if env_value is not None:
|
40
|
+
logger.debug(f"Overriding {key} setting from environment variable.")
|
41
|
+
return env_value
|
42
|
+
|
43
|
+
|
26
44
|
class SettingsManager:
|
27
45
|
"""
|
28
46
|
Manager for handling application settings with database storage and file fallback.
|
@@ -37,30 +55,29 @@ class SettingsManager:
|
|
37
55
|
db_session: SQLAlchemy session for database operations
|
38
56
|
"""
|
39
57
|
self.db_session = db_session
|
40
|
-
self.config_dir = get_config_dir() / "config"
|
41
|
-
self.settings_file = self.config_dir / "settings.toml"
|
42
|
-
self.search_engines_file = self.config_dir / "search_engines.toml"
|
43
|
-
self.collections_file = self.config_dir / "local_collections.toml"
|
44
|
-
self.secrets_file = self.config_dir / ".secrets.toml"
|
45
58
|
self.db_first = True # Always prioritize DB settings
|
46
59
|
|
47
|
-
#
|
48
|
-
|
60
|
+
# Load default settings.
|
61
|
+
default_settings = pkg_resources.read_text(defaults, "default_settings.json")
|
62
|
+
self.default_settings = json.loads(default_settings)
|
49
63
|
|
50
|
-
def get_setting(self, key: str, default: Any = None) -> Any:
|
64
|
+
def get_setting(self, key: str, default: Any = None, check_env: bool = True) -> Any:
|
51
65
|
"""
|
52
66
|
Get a setting value
|
53
67
|
|
54
68
|
Args:
|
55
69
|
key: Setting key
|
56
70
|
default: Default value if setting is not found
|
71
|
+
check_env: If true, it will check the environment variable for
|
72
|
+
this setting before reading from the DB.
|
57
73
|
|
58
74
|
Returns:
|
59
75
|
Setting value or default if not found
|
60
76
|
"""
|
61
|
-
|
62
|
-
|
63
|
-
|
77
|
+
if check_env:
|
78
|
+
env_value = check_env_setting(key)
|
79
|
+
if env_value is not None:
|
80
|
+
return env_value
|
64
81
|
|
65
82
|
# If using database first approach and session available, check database
|
66
83
|
if self.db_first and self.db_session:
|
@@ -73,7 +90,6 @@ class SettingsManager:
|
|
73
90
|
if len(settings) == 1:
|
74
91
|
# This is a bottom-level key.
|
75
92
|
value = settings[0].value
|
76
|
-
self._settings_cache[key] = value
|
77
93
|
return value
|
78
94
|
elif len(settings) > 1:
|
79
95
|
# This is a higher-level key.
|
@@ -86,22 +102,6 @@ class SettingsManager:
|
|
86
102
|
except SQLAlchemyError as e:
|
87
103
|
logger.error(f"Error retrieving setting {key} from database: {e}")
|
88
104
|
|
89
|
-
# Fall back to Dynaconf settings
|
90
|
-
try:
|
91
|
-
# Split the key into sections
|
92
|
-
parts = key.split(".")
|
93
|
-
if len(parts) == 2:
|
94
|
-
section, setting = parts
|
95
|
-
if hasattr(dynaconf_settings, section) and hasattr(
|
96
|
-
getattr(dynaconf_settings, section), setting
|
97
|
-
):
|
98
|
-
value = getattr(getattr(dynaconf_settings, section), setting)
|
99
|
-
# Update cache and return
|
100
|
-
self._settings_cache[key] = value
|
101
|
-
return value
|
102
|
-
except Exception as e:
|
103
|
-
logger.debug(f"Error retrieving setting {key} from Dynaconf: {e}")
|
104
|
-
|
105
105
|
# Return default if not found
|
106
106
|
return default
|
107
107
|
|
@@ -117,9 +117,6 @@ class SettingsManager:
|
|
117
117
|
Returns:
|
118
118
|
True if successful, False otherwise
|
119
119
|
"""
|
120
|
-
# Always update cache
|
121
|
-
self._settings_cache[key] = value
|
122
|
-
|
123
120
|
# Always update database if available
|
124
121
|
if self.db_session:
|
125
122
|
try:
|
@@ -172,29 +169,36 @@ class SettingsManager:
|
|
172
169
|
"""
|
173
170
|
result = {}
|
174
171
|
|
175
|
-
# Start with memory cache (highest priority)
|
176
|
-
result.update(self._settings_cache)
|
177
|
-
|
178
172
|
# Add database settings if available
|
179
173
|
if self.db_session:
|
180
174
|
try:
|
181
175
|
for setting in self.db_session.query(Setting).all():
|
182
|
-
result[setting.key] =
|
176
|
+
result[setting.key] = dict(
|
177
|
+
value=setting.value,
|
178
|
+
type=setting.type.name,
|
179
|
+
name=setting.name,
|
180
|
+
description=setting.description,
|
181
|
+
category=setting.category,
|
182
|
+
ui_element=setting.ui_element,
|
183
|
+
options=setting.options,
|
184
|
+
min_value=setting.min_value,
|
185
|
+
max_value=setting.max_value,
|
186
|
+
step=setting.step,
|
187
|
+
visible=setting.visible,
|
188
|
+
editable=setting.editable,
|
189
|
+
)
|
190
|
+
|
191
|
+
# Override from the environment variables if needed.
|
192
|
+
env_value = check_env_setting(setting.key)
|
193
|
+
if env_value is not None:
|
194
|
+
result[setting.key]["value"] = env_value
|
195
|
+
# Mark it as non-editable, because changes to the DB
|
196
|
+
# value have no effect as long as the environment
|
197
|
+
# variable is set.
|
198
|
+
result[setting.key]["editable"] = False
|
183
199
|
except SQLAlchemyError as e:
|
184
200
|
logger.error(f"Error retrieving all settings from database: {e}")
|
185
201
|
|
186
|
-
# Fill in missing values from Dynaconf (lowest priority)
|
187
|
-
for section in ["llm", "search", "report", "app", "web"]:
|
188
|
-
if hasattr(dynaconf_settings, section):
|
189
|
-
section_obj = getattr(dynaconf_settings, section)
|
190
|
-
for key in dir(section_obj):
|
191
|
-
if not key.startswith("_") and not callable(
|
192
|
-
getattr(section_obj, key)
|
193
|
-
):
|
194
|
-
full_key = f"{section}.{key}"
|
195
|
-
if full_key not in result:
|
196
|
-
result[full_key] = getattr(section_obj, key)
|
197
|
-
|
198
202
|
return result
|
199
203
|
|
200
204
|
def create_or_update_setting(
|
@@ -278,9 +282,6 @@ class SettingsManager:
|
|
278
282
|
)
|
279
283
|
self.db_session.add(db_setting)
|
280
284
|
|
281
|
-
# Update cache
|
282
|
-
self._settings_cache[setting_obj.key] = setting_obj.value
|
283
|
-
|
284
285
|
if commit:
|
285
286
|
self.db_session.commit()
|
286
287
|
|
@@ -307,10 +308,6 @@ class SettingsManager:
|
|
307
308
|
return False
|
308
309
|
|
309
310
|
try:
|
310
|
-
# Remove from cache
|
311
|
-
if key in self._settings_cache:
|
312
|
-
del self._settings_cache[key]
|
313
|
-
|
314
311
|
# Remove from database
|
315
312
|
result = self.db_session.query(Setting).filter(Setting.key == key).delete()
|
316
313
|
|
@@ -323,181 +320,32 @@ class SettingsManager:
|
|
323
320
|
self.db_session.rollback()
|
324
321
|
return False
|
325
322
|
|
326
|
-
def
|
323
|
+
def load_from_defaults_file(self, commit: bool = True, **kwargs: Any) -> None:
|
327
324
|
"""
|
328
|
-
|
325
|
+
Import settings from the defaults settings file.
|
329
326
|
|
330
327
|
Args:
|
331
|
-
|
328
|
+
commit: Whether to commit changes to database
|
329
|
+
**kwargs: Will be passed to `import_settings`.
|
332
330
|
|
333
|
-
Returns:
|
334
|
-
True if successful, False otherwise
|
335
331
|
"""
|
336
|
-
|
337
|
-
# Get settings
|
338
|
-
settings = self.get_all_settings()
|
339
|
-
|
340
|
-
# Group by section
|
341
|
-
sections = {}
|
342
|
-
for key, value in settings.items():
|
343
|
-
# Split key into section and name
|
344
|
-
parts = key.split(".", 1)
|
345
|
-
if len(parts) == 2:
|
346
|
-
section, name = parts
|
347
|
-
if section not in sections:
|
348
|
-
sections[section] = {}
|
349
|
-
sections[section][name] = value
|
350
|
-
|
351
|
-
# Write to appropriate file
|
352
|
-
if setting_type == SettingType.LLM:
|
353
|
-
file_path = self.settings_file
|
354
|
-
section_name = "llm"
|
355
|
-
elif setting_type == SettingType.SEARCH:
|
356
|
-
file_path = self.search_engines_file
|
357
|
-
section_name = "search"
|
358
|
-
elif setting_type == SettingType.REPORT:
|
359
|
-
file_path = self.settings_file
|
360
|
-
section_name = "report"
|
361
|
-
else:
|
362
|
-
# Write all sections to appropriate files
|
363
|
-
for section_name, section_data in sections.items():
|
364
|
-
if section_name == "search":
|
365
|
-
self._write_section_to_file(
|
366
|
-
self.search_engines_file, section_name, section_data
|
367
|
-
)
|
368
|
-
else:
|
369
|
-
self._write_section_to_file(
|
370
|
-
self.settings_file, section_name, section_data
|
371
|
-
)
|
372
|
-
return True
|
373
|
-
|
374
|
-
# Write specific section
|
375
|
-
if section_name in sections:
|
376
|
-
return self._write_section_to_file(
|
377
|
-
file_path, section_name, sections[section_name]
|
378
|
-
)
|
379
|
-
|
380
|
-
return False
|
381
|
-
|
382
|
-
except Exception as e:
|
383
|
-
logger.error(f"Error exporting settings to file: {e}")
|
384
|
-
return False
|
332
|
+
self.import_settings(self.default_settings, commit=commit, **kwargs)
|
385
333
|
|
386
|
-
def
|
387
|
-
self, setting_type: Optional[SettingType] = None, commit: bool = True
|
388
|
-
) -> bool:
|
334
|
+
def db_version_matches_defaults(self) -> bool:
|
389
335
|
"""
|
390
|
-
Import settings from file
|
391
|
-
|
392
|
-
Args:
|
393
|
-
setting_type: Type of settings to import (or all if None)
|
394
|
-
commit: Whether to commit changes to database
|
395
|
-
|
396
336
|
Returns:
|
397
|
-
True if
|
398
|
-
|
399
|
-
try:
|
400
|
-
# Determine file path
|
401
|
-
if (
|
402
|
-
setting_type == SettingType.LLM
|
403
|
-
or setting_type == SettingType.APP
|
404
|
-
or setting_type == SettingType.REPORT
|
405
|
-
):
|
406
|
-
file_path = self.settings_file
|
407
|
-
elif setting_type == SettingType.SEARCH:
|
408
|
-
file_path = self.search_engines_file
|
409
|
-
else:
|
410
|
-
# Import from all files
|
411
|
-
success = True
|
412
|
-
success &= self.import_from_file(SettingType.LLM, commit=False)
|
413
|
-
success &= self.import_from_file(SettingType.SEARCH, commit=False)
|
414
|
-
success &= self.import_from_file(SettingType.REPORT, commit=False)
|
415
|
-
success &= self.import_from_file(SettingType.APP, commit=False)
|
416
|
-
|
417
|
-
# Commit all changes at once
|
418
|
-
if commit and self.db_session:
|
419
|
-
self.db_session.commit()
|
420
|
-
|
421
|
-
return success
|
422
|
-
|
423
|
-
# Read from file
|
424
|
-
if not os.path.exists(file_path):
|
425
|
-
logger.warning(f"Settings file does not exist: {file_path}")
|
426
|
-
return False
|
427
|
-
|
428
|
-
# Parse TOML file
|
429
|
-
with open(file_path, "r") as f:
|
430
|
-
file_data = toml.load(f)
|
431
|
-
|
432
|
-
# Extract section based on setting type
|
433
|
-
section_name = setting_type.value.lower() if setting_type else None
|
434
|
-
if section_name and section_name in file_data:
|
435
|
-
section_data = file_data[section_name]
|
436
|
-
else:
|
437
|
-
section_data = file_data
|
438
|
-
|
439
|
-
# Import settings
|
440
|
-
for key, value in section_data.items():
|
441
|
-
if section_name:
|
442
|
-
full_key = f"{section_name}.{key}"
|
443
|
-
else:
|
444
|
-
# Try to determine section from key structure
|
445
|
-
if "." in key:
|
446
|
-
full_key = key
|
447
|
-
else:
|
448
|
-
# Assume it's an app setting
|
449
|
-
full_key = f"app.{key}"
|
450
|
-
|
451
|
-
self.set_setting(full_key, value, commit=False)
|
452
|
-
|
453
|
-
# Commit if requested
|
454
|
-
if commit and self.db_session:
|
455
|
-
self.db_session.commit()
|
456
|
-
|
457
|
-
return True
|
337
|
+
True if the version saved in the DB matches that in the default
|
338
|
+
settings file.
|
458
339
|
|
459
|
-
except Exception as e:
|
460
|
-
logger.error(f"Error importing settings from file: {e}")
|
461
|
-
if self.db_session:
|
462
|
-
self.db_session.rollback()
|
463
|
-
return False
|
464
|
-
|
465
|
-
def _write_section_to_file(
|
466
|
-
self, file_path: Path, section: str, data: Dict[str, Any]
|
467
|
-
) -> bool:
|
468
340
|
"""
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
341
|
+
db_version = self.get_setting("app.version")
|
342
|
+
default_version = self.default_settings["app.version"]["value"]
|
343
|
+
logger.debug(
|
344
|
+
f"App version saved in DB is {db_version}, have default "
|
345
|
+
f"settings from version {default_version}."
|
346
|
+
)
|
475
347
|
|
476
|
-
|
477
|
-
True if successful, False otherwise
|
478
|
-
"""
|
479
|
-
try:
|
480
|
-
# Create file if it doesn't exist
|
481
|
-
if not os.path.exists(file_path):
|
482
|
-
file_path.parent.mkdir(parents=True, exist_ok=True)
|
483
|
-
with open(file_path, "w") as f:
|
484
|
-
f.write(f"[{section}]\n")
|
485
|
-
|
486
|
-
# Read existing file
|
487
|
-
with open(file_path, "r") as f:
|
488
|
-
file_data = toml.load(f)
|
489
|
-
|
490
|
-
# Update section
|
491
|
-
file_data[section] = data
|
492
|
-
|
493
|
-
# Write back to file
|
494
|
-
with open(file_path, "w") as f:
|
495
|
-
toml.dump(file_data, f)
|
496
|
-
|
497
|
-
return True
|
498
|
-
except Exception as e:
|
499
|
-
logger.error(f"Error writing section {section} to {file_path}: {e}")
|
500
|
-
return False
|
348
|
+
return db_version == default_version
|
501
349
|
|
502
350
|
@classmethod
|
503
351
|
def get_instance(cls, db_session: Optional[Session] = None) -> "SettingsManager":
|
@@ -518,100 +366,49 @@ class SettingsManager:
|
|
518
366
|
|
519
367
|
return cls._instance
|
520
368
|
|
521
|
-
def
|
522
|
-
self,
|
523
|
-
|
369
|
+
def import_settings(
|
370
|
+
self,
|
371
|
+
settings_data: Dict[str, Any],
|
372
|
+
commit: bool = True,
|
373
|
+
overwrite: bool = True,
|
374
|
+
delete_extra: bool = False,
|
375
|
+
) -> None:
|
524
376
|
"""
|
525
|
-
Import settings directly from
|
377
|
+
Import settings directly from the export format. This can be used to
|
378
|
+
re-import settings that have been exported with `get_all_settings()`.
|
526
379
|
|
527
380
|
Args:
|
528
|
-
|
529
|
-
|
530
|
-
|
381
|
+
settings_data: The raw settings data to import.
|
382
|
+
commit: Whether to commit the DB after loading the settings.
|
383
|
+
overwrite: If true, it will overwrite the value of settings that
|
384
|
+
are already in the database.
|
385
|
+
delete_extra: If true, it will delete any settings that are in
|
386
|
+
the database but don't have a corresponding entry in
|
387
|
+
`settings_data`.
|
531
388
|
|
532
|
-
Returns:
|
533
|
-
True if successful, False otherwise
|
534
389
|
"""
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
#
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
prefix = "llm"
|
557
|
-
else: # general section
|
558
|
-
# Map general settings to appropriate types
|
559
|
-
prefix = None
|
560
|
-
for key, value in values.items():
|
561
|
-
if key in [
|
562
|
-
"enable_fact_checking",
|
563
|
-
"knowledge_accumulation",
|
564
|
-
"knowledge_accumulation_context_limit",
|
565
|
-
"output_dir",
|
566
|
-
]:
|
567
|
-
self._create_setting(
|
568
|
-
f"report.{key}", value, SettingType.REPORT
|
569
|
-
)
|
570
|
-
|
571
|
-
# Add settings with correct prefix
|
572
|
-
if prefix:
|
573
|
-
for key, value in values.items():
|
574
|
-
self._create_setting(
|
575
|
-
f"{prefix}.{key}", value, setting_type
|
576
|
-
)
|
577
|
-
|
578
|
-
elif section == "search":
|
579
|
-
# Search settings go to search type
|
580
|
-
for key, value in values.items():
|
581
|
-
self._create_setting(
|
582
|
-
f"search.{key}", value, SettingType.SEARCH
|
583
|
-
)
|
584
|
-
|
585
|
-
elif section == "report":
|
586
|
-
# Report settings
|
587
|
-
for key, value in values.items():
|
588
|
-
self._create_setting(
|
589
|
-
f"report.{key}", value, SettingType.REPORT
|
590
|
-
)
|
591
|
-
|
592
|
-
# Import settings from search engines file
|
593
|
-
if os.path.exists(search_engines_file):
|
594
|
-
with open(search_engines_file, "r") as f:
|
595
|
-
search_data = toml.load(f)
|
596
|
-
|
597
|
-
# Find search section in search engines file
|
598
|
-
if "search" in search_data:
|
599
|
-
for key, value in search_data["search"].items():
|
600
|
-
# Skip complex sections that are nested
|
601
|
-
if not isinstance(value, dict):
|
602
|
-
self._create_setting(
|
603
|
-
f"search.{key}", value, SettingType.SEARCH
|
604
|
-
)
|
605
|
-
|
606
|
-
# Commit changes
|
390
|
+
for key, setting_values in settings_data.items():
|
391
|
+
if not overwrite:
|
392
|
+
existing_value = self.get_setting(key)
|
393
|
+
if existing_value is not None:
|
394
|
+
# Preserve the value from this setting.
|
395
|
+
setting_values["value"] = existing_value
|
396
|
+
|
397
|
+
# Delete any existing setting so we can completely overwrite it.
|
398
|
+
self.delete_setting(key, commit=False)
|
399
|
+
|
400
|
+
setting = Setting(key=key, **setting_values)
|
401
|
+
self.db_session.add(setting)
|
402
|
+
|
403
|
+
if delete_extra:
|
404
|
+
all_settings = self.get_all_settings()
|
405
|
+
for key in all_settings:
|
406
|
+
if key not in settings_data:
|
407
|
+
logger.debug(f"Deleting extraneous setting: {key}")
|
408
|
+
self.delete_setting(key, commit=False)
|
409
|
+
|
410
|
+
if commit:
|
607
411
|
self.db_session.commit()
|
608
|
-
return True
|
609
|
-
|
610
|
-
except Exception as e:
|
611
|
-
logger.error(f"Error importing default settings: {e}")
|
612
|
-
if self.db_session:
|
613
|
-
self.db_session.rollback()
|
614
|
-
return False
|
615
412
|
|
616
413
|
def _create_setting(self, key, value, setting_type):
|
617
414
|
"""Create a setting with appropriate metadata"""
|
@@ -662,8 +459,4 @@ class SettingsManager:
|
|
662
459
|
}
|
663
460
|
|
664
461
|
# Create the setting in the database
|
665
|
-
|
666
|
-
|
667
|
-
# Also update cache
|
668
|
-
if db_setting:
|
669
|
-
self._settings_cache[key] = value
|
462
|
+
self.create_or_update_setting(setting_dict, commit=False)
|
@@ -1,8 +1,7 @@
|
|
1
1
|
import logging
|
2
|
-
from pathlib import Path
|
3
2
|
from typing import Any, Dict, Optional, Union
|
4
3
|
|
5
|
-
from ..database.models import Setting
|
4
|
+
from ..database.models import Setting
|
6
5
|
from .settings_manager import SettingsManager
|
7
6
|
|
8
7
|
# Initialize logger
|
@@ -55,46 +54,18 @@ def set_setting(key: str, value: Any, commit: bool = True, db_session=None) -> b
|
|
55
54
|
return manager.set_setting(key, value, commit)
|
56
55
|
|
57
56
|
|
58
|
-
def get_all_settings(
|
59
|
-
setting_type: Optional[SettingType] = None, db_session=None
|
60
|
-
) -> Dict[str, Any]:
|
57
|
+
def get_all_settings(db_session=None) -> Dict[str, Any]:
|
61
58
|
"""
|
62
59
|
Get all settings, optionally filtered by type
|
63
60
|
|
64
61
|
Args:
|
65
|
-
setting_type: Optional filter by type
|
66
62
|
db_session: Optional database session
|
67
63
|
|
68
64
|
Returns:
|
69
65
|
Dict[str, Any]: Dictionary of settings
|
70
66
|
"""
|
71
67
|
manager = get_settings_manager(db_session)
|
72
|
-
return manager.get_all_settings(
|
73
|
-
|
74
|
-
|
75
|
-
def get_all_settings_as_dict(db_session=None) -> Dict[str, Dict[str, Any]]:
|
76
|
-
"""
|
77
|
-
Get all settings as a structured dictionary
|
78
|
-
|
79
|
-
Args:
|
80
|
-
db_session: Optional database session
|
81
|
-
|
82
|
-
Returns:
|
83
|
-
Dict[str, Dict[str, Any]]: Dictionary of settings grouped by type
|
84
|
-
"""
|
85
|
-
# Get settings manager
|
86
|
-
manager = get_settings_manager(db_session)
|
87
|
-
|
88
|
-
# Get all settings
|
89
|
-
all_settings = {}
|
90
|
-
|
91
|
-
for setting_type in SettingType:
|
92
|
-
type_key = setting_type.value.lower()
|
93
|
-
type_settings = manager.get_all_settings(setting_type)
|
94
|
-
if type_settings:
|
95
|
-
all_settings[type_key] = type_settings
|
96
|
-
|
97
|
-
return all_settings
|
68
|
+
return manager.get_all_settings()
|
98
69
|
|
99
70
|
|
100
71
|
def create_or_update_setting(
|
@@ -147,30 +118,6 @@ def bulk_update_settings(
|
|
147
118
|
return success
|
148
119
|
|
149
120
|
|
150
|
-
def import_settings_from_file(
|
151
|
-
main_settings_file: Union[str, Path],
|
152
|
-
search_engines_file: Union[str, Path],
|
153
|
-
collections_file: Union[str, Path],
|
154
|
-
db_session=None,
|
155
|
-
) -> bool:
|
156
|
-
"""
|
157
|
-
Import settings from default configuration files
|
158
|
-
|
159
|
-
Args:
|
160
|
-
main_settings_file: Path to the main settings file
|
161
|
-
search_engines_file: Path to the search engines file
|
162
|
-
collections_file: Path to the collections file
|
163
|
-
db_session: Optional database session
|
164
|
-
|
165
|
-
Returns:
|
166
|
-
bool: True if import was successful
|
167
|
-
"""
|
168
|
-
manager = get_settings_manager(db_session)
|
169
|
-
return manager.import_default_settings(
|
170
|
-
main_settings_file, search_engines_file, collections_file
|
171
|
-
)
|
172
|
-
|
173
|
-
|
174
121
|
def validate_setting(setting: Setting, value: Any) -> tuple[bool, Optional[str]]:
|
175
122
|
"""
|
176
123
|
Validate a setting value based on its type and constraints
|
@@ -1043,7 +1043,7 @@
|
|
1043
1043
|
// Find the provider and model settings
|
1044
1044
|
const providerSetting = data.settings.value["provider"];
|
1045
1045
|
const modelSetting = data.settings.value["model"];
|
1046
|
-
const customEndpointUrl = data.settings.value["
|
1046
|
+
const customEndpointUrl = data.settings.value["openai_endpoint.url"];
|
1047
1047
|
|
1048
1048
|
// Update provider dropdown if we have a valid provider
|
1049
1049
|
if (providerSetting && modelProviderSelect) {
|