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
@@ -3,11 +3,9 @@ import logging
|
|
3
3
|
import os
|
4
4
|
import platform
|
5
5
|
import subprocess
|
6
|
-
from pathlib import Path
|
7
6
|
from typing import Any, Optional, Tuple
|
8
7
|
|
9
8
|
import requests
|
10
|
-
import toml
|
11
9
|
from flask import (
|
12
10
|
Blueprint,
|
13
11
|
current_app,
|
@@ -21,8 +19,6 @@ from flask import (
|
|
21
19
|
from flask_wtf.csrf import generate_csrf
|
22
20
|
from sqlalchemy.orm import Session
|
23
21
|
|
24
|
-
from ...config.config_files import get_config_dir
|
25
|
-
from ...web_search_engines.search_engine_factory import get_available_engines
|
26
22
|
from ..database.models import Setting, SettingType
|
27
23
|
from ..services.settings_service import (
|
28
24
|
create_or_update_setting,
|
@@ -37,23 +33,6 @@ logger = logging.getLogger(__name__)
|
|
37
33
|
# Create a Blueprint for settings
|
38
34
|
settings_bp = Blueprint("settings", __name__, url_prefix="/research/settings")
|
39
35
|
|
40
|
-
# Legacy config for backwards compatibility
|
41
|
-
SEARCH_ENGINES_FILE = None
|
42
|
-
CONFIG_DIR = None
|
43
|
-
MAIN_CONFIG_FILE = None
|
44
|
-
LOCAL_COLLECTIONS_FILE = None
|
45
|
-
|
46
|
-
|
47
|
-
def set_config_paths(
|
48
|
-
config_dir, search_engines_file, main_config_file, local_collections_file
|
49
|
-
):
|
50
|
-
"""Set the config paths for the settings routes (legacy support)"""
|
51
|
-
global CONFIG_DIR, SEARCH_ENGINES_FILE, MAIN_CONFIG_FILE, LOCAL_COLLECTIONS_FILE
|
52
|
-
CONFIG_DIR = config_dir
|
53
|
-
SEARCH_ENGINES_FILE = search_engines_file
|
54
|
-
MAIN_CONFIG_FILE = main_config_file
|
55
|
-
LOCAL_COLLECTIONS_FILE = local_collections_file
|
56
|
-
|
57
36
|
|
58
37
|
def get_db_session() -> Session:
|
59
38
|
"""Get the database session from the app context"""
|
@@ -105,56 +84,6 @@ def validate_setting(setting: Setting, value: Any) -> Tuple[bool, Optional[str]]
|
|
105
84
|
return True, None
|
106
85
|
|
107
86
|
|
108
|
-
def get_all_settings_json():
|
109
|
-
"""Get all settings as a JSON-serializable dictionary
|
110
|
-
|
111
|
-
Returns:
|
112
|
-
List of setting dictionaries
|
113
|
-
"""
|
114
|
-
db_session = get_db_session()
|
115
|
-
settings_list = []
|
116
|
-
|
117
|
-
# Get all settings
|
118
|
-
settings = (
|
119
|
-
db_session.query(Setting)
|
120
|
-
.order_by(Setting.type, Setting.category, Setting.name)
|
121
|
-
.all()
|
122
|
-
)
|
123
|
-
|
124
|
-
# Convert to dictionaries
|
125
|
-
for setting in settings:
|
126
|
-
# Ensure objects are properly serialized
|
127
|
-
value = setting.value
|
128
|
-
|
129
|
-
# Convert objects to properly formatted JSON strings for display
|
130
|
-
if isinstance(value, (dict, list)) and value:
|
131
|
-
try:
|
132
|
-
# For frontend display, we'll keep objects as they are
|
133
|
-
# The javascript will handle formatting them
|
134
|
-
pass
|
135
|
-
except Exception as e:
|
136
|
-
logger.error(f"Error serializing setting {setting.key}: {e}")
|
137
|
-
|
138
|
-
setting_dict = {
|
139
|
-
"key": setting.key,
|
140
|
-
"value": value,
|
141
|
-
"type": setting.type.value if setting.type else None,
|
142
|
-
"name": setting.name,
|
143
|
-
"description": setting.description,
|
144
|
-
"category": setting.category,
|
145
|
-
"ui_element": setting.ui_element,
|
146
|
-
"options": setting.options,
|
147
|
-
"min_value": setting.min_value,
|
148
|
-
"max_value": setting.max_value,
|
149
|
-
"step": setting.step,
|
150
|
-
"visible": setting.visible,
|
151
|
-
"editable": setting.editable,
|
152
|
-
}
|
153
|
-
settings_list.append(setting_dict)
|
154
|
-
|
155
|
-
return settings_list
|
156
|
-
|
157
|
-
|
158
87
|
@settings_bp.route("/", methods=["GET"])
|
159
88
|
def settings_page():
|
160
89
|
"""Main settings dashboard with links to specialized config pages"""
|
@@ -202,7 +131,6 @@ def save_all_settings():
|
|
202
131
|
original_values[key] = current_setting.value
|
203
132
|
|
204
133
|
# Determine setting type and category
|
205
|
-
setting_type = None
|
206
134
|
if key.startswith("llm."):
|
207
135
|
setting_type = SettingType.LLM
|
208
136
|
category = "llm_general"
|
@@ -231,9 +159,8 @@ def save_all_settings():
|
|
231
159
|
setting_type = SettingType.APP
|
232
160
|
category = "app_interface"
|
233
161
|
else:
|
234
|
-
|
235
|
-
|
236
|
-
continue
|
162
|
+
setting_type = None
|
163
|
+
category = None
|
237
164
|
|
238
165
|
# Special handling for corrupted or empty values
|
239
166
|
if value == "[object Object]" or (
|
@@ -276,10 +203,6 @@ def save_all_settings():
|
|
276
203
|
is_valid, error_message = validate_setting(current_setting, value)
|
277
204
|
|
278
205
|
if is_valid:
|
279
|
-
# Update category if different from our determination
|
280
|
-
if category and current_setting.category != category:
|
281
|
-
current_setting.category = category
|
282
|
-
|
283
206
|
# Save the setting
|
284
207
|
success = set_setting(key, value, db_session=db_session)
|
285
208
|
if success:
|
@@ -425,128 +348,37 @@ def save_all_settings():
|
|
425
348
|
)
|
426
349
|
|
427
350
|
|
428
|
-
@settings_bp.route("/reset_to_defaults", methods=["
|
351
|
+
@settings_bp.route("/reset_to_defaults", methods=["GET"])
|
429
352
|
def reset_to_defaults():
|
430
353
|
"""Reset all settings to their default values"""
|
431
354
|
db_session = get_db_session()
|
432
355
|
|
356
|
+
# Import default settings from files
|
433
357
|
try:
|
434
|
-
#
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
logger.info(f"Deleting {settings_count} existing settings before reset")
|
439
|
-
|
440
|
-
# Delete all settings
|
441
|
-
db_session.query(Setting).delete()
|
442
|
-
db_session.commit()
|
443
|
-
logger.info("Successfully deleted all existing settings")
|
444
|
-
except Exception as e:
|
445
|
-
logger.error(f"Error deleting existing settings: {e}")
|
446
|
-
db_session.rollback()
|
447
|
-
return (
|
448
|
-
jsonify(
|
449
|
-
{
|
450
|
-
"status": "error",
|
451
|
-
"message": f"Error cleaning existing settings: {str(e)}",
|
452
|
-
}
|
453
|
-
),
|
454
|
-
500,
|
455
|
-
)
|
456
|
-
|
457
|
-
# Import default settings from files
|
458
|
-
try:
|
459
|
-
# Import default config files from the defaults directory
|
460
|
-
from importlib.resources import files
|
461
|
-
|
462
|
-
try:
|
463
|
-
defaults_dir = files("local_deep_research.defaults")
|
464
|
-
except ImportError:
|
465
|
-
# Fallback for older Python versions
|
466
|
-
from pkg_resources import resource_filename
|
358
|
+
# Create settings manager for the temporary config
|
359
|
+
settings_mgr = get_settings_manager(db_session)
|
360
|
+
# Import settings from default files
|
361
|
+
settings_mgr.load_from_defaults_file()
|
467
362
|
|
468
|
-
|
469
|
-
resource_filename("local_deep_research", "defaults")
|
470
|
-
)
|
471
|
-
|
472
|
-
logger.info(f"Loading defaults from: {defaults_dir}")
|
473
|
-
|
474
|
-
# Get temporary path to default files
|
475
|
-
import tempfile
|
476
|
-
|
477
|
-
with tempfile.TemporaryDirectory() as temp_dir:
|
478
|
-
# Copy default files to temp directory
|
479
|
-
temp_main = Path(temp_dir) / "settings.toml"
|
480
|
-
temp_search = Path(temp_dir) / "search_engines.toml"
|
481
|
-
temp_collections = Path(temp_dir) / "local_collections.toml"
|
482
|
-
|
483
|
-
# Copy default files (platform independent)
|
484
|
-
import importlib.resources as pkg_resources
|
485
|
-
|
486
|
-
from ... import defaults
|
487
|
-
|
488
|
-
with open(temp_main, "wb") as f:
|
489
|
-
f.write(pkg_resources.read_binary(defaults, "main.toml"))
|
490
|
-
|
491
|
-
with open(temp_search, "wb") as f:
|
492
|
-
f.write(pkg_resources.read_binary(defaults, "search_engines.toml"))
|
493
|
-
|
494
|
-
with open(temp_collections, "wb") as f:
|
495
|
-
f.write(
|
496
|
-
pkg_resources.read_binary(defaults, "local_collections.toml")
|
497
|
-
)
|
498
|
-
|
499
|
-
# Create settings manager with temp files
|
500
|
-
# Get configuration directory (not used currently but might be needed in future)
|
501
|
-
# config_dir = get_config_dir() / "config"
|
502
|
-
|
503
|
-
# Create settings manager for the temporary config
|
504
|
-
settings_mgr = get_settings_manager(db_session)
|
505
|
-
|
506
|
-
# Import settings from default files
|
507
|
-
settings_mgr.import_default_settings(
|
508
|
-
temp_main, temp_search, temp_collections
|
509
|
-
)
|
510
|
-
|
511
|
-
logger.info("Successfully imported settings from default files")
|
512
|
-
except Exception as e:
|
513
|
-
logger.error(f"Error importing default settings: {e}")
|
514
|
-
|
515
|
-
# Fallback to predefined settings if file import fails
|
516
|
-
logger.info("Falling back to predefined settings")
|
517
|
-
# Import here to avoid circular imports
|
518
|
-
from ..database.migrations import (
|
519
|
-
setup_predefined_settings as setup_settings,
|
520
|
-
)
|
521
|
-
|
522
|
-
setup_settings(db_session)
|
523
|
-
|
524
|
-
# Return success
|
525
|
-
return jsonify(
|
526
|
-
{
|
527
|
-
"status": "success",
|
528
|
-
"message": "All settings have been reset to default values",
|
529
|
-
}
|
530
|
-
)
|
363
|
+
logger.info("Successfully imported settings from default files")
|
531
364
|
|
532
365
|
except Exception as e:
|
533
|
-
logger.error(f"Error
|
534
|
-
return (
|
535
|
-
jsonify(
|
536
|
-
{
|
537
|
-
"status": "error",
|
538
|
-
"message": f"Error resetting settings to defaults: {str(e)}",
|
539
|
-
}
|
540
|
-
),
|
541
|
-
500,
|
542
|
-
)
|
366
|
+
logger.error(f"Error importing default settings: {e}")
|
543
367
|
|
368
|
+
# Fallback to predefined settings if file import fails
|
369
|
+
logger.info("Falling back to predefined settings")
|
370
|
+
# Import here to avoid circular imports
|
371
|
+
from ..database.migrations import setup_predefined_settings as setup_settings
|
544
372
|
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
373
|
+
setup_settings(db_session)
|
374
|
+
|
375
|
+
# Return success
|
376
|
+
return jsonify(
|
377
|
+
{
|
378
|
+
"status": "success",
|
379
|
+
"message": "All settings have been reset to default values",
|
380
|
+
}
|
381
|
+
)
|
550
382
|
|
551
383
|
|
552
384
|
# API Routes
|
@@ -555,7 +387,6 @@ def api_get_all_settings():
|
|
555
387
|
"""Get all settings"""
|
556
388
|
try:
|
557
389
|
# Get query parameters
|
558
|
-
setting_type = request.args.get("type")
|
559
390
|
category = request.args.get("category")
|
560
391
|
|
561
392
|
# Create settings manager
|
@@ -563,14 +394,7 @@ def api_get_all_settings():
|
|
563
394
|
settings_manager = get_settings_manager(db_session)
|
564
395
|
|
565
396
|
# Get settings
|
566
|
-
|
567
|
-
try:
|
568
|
-
setting_type_enum = SettingType[setting_type.upper()]
|
569
|
-
settings = settings_manager.get_all_settings(setting_type_enum)
|
570
|
-
except KeyError:
|
571
|
-
return jsonify({"error": f"Invalid setting type: {setting_type}"}), 400
|
572
|
-
else:
|
573
|
-
settings = settings_manager.get_all_settings()
|
397
|
+
settings = settings_manager.get_all_settings()
|
574
398
|
|
575
399
|
# Filter by category if requested
|
576
400
|
if category:
|
@@ -586,7 +410,7 @@ def api_get_all_settings():
|
|
586
410
|
|
587
411
|
settings = filtered_settings
|
588
412
|
|
589
|
-
return jsonify({"settings": settings})
|
413
|
+
return jsonify({"status": "success", "settings": settings})
|
590
414
|
except Exception as e:
|
591
415
|
logger.error(f"Error getting settings: {e}")
|
592
416
|
return jsonify({"error": str(e)}), 500
|
@@ -741,60 +565,14 @@ def api_delete_setting(key):
|
|
741
565
|
return jsonify({"error": str(e)}), 500
|
742
566
|
|
743
567
|
|
744
|
-
@settings_bp.route("/api/export", methods=["POST"])
|
745
|
-
def api_export_settings():
|
746
|
-
"""Export settings to file"""
|
747
|
-
try:
|
748
|
-
data = request.get_json() or {}
|
749
|
-
setting_type_str = data.get("type")
|
750
|
-
|
751
|
-
db_session = get_db_session()
|
752
|
-
settings_manager = get_settings_manager(db_session)
|
753
|
-
|
754
|
-
# Export settings
|
755
|
-
if setting_type_str:
|
756
|
-
try:
|
757
|
-
setting_type = SettingType[setting_type_str.upper()]
|
758
|
-
success = settings_manager.export_to_file(setting_type)
|
759
|
-
except KeyError:
|
760
|
-
return (
|
761
|
-
jsonify({"error": f"Invalid setting type: {setting_type_str}"}),
|
762
|
-
400,
|
763
|
-
)
|
764
|
-
else:
|
765
|
-
success = settings_manager.export_to_file()
|
766
|
-
|
767
|
-
if success:
|
768
|
-
return jsonify({"message": "Settings exported successfully"})
|
769
|
-
else:
|
770
|
-
return jsonify({"error": "Failed to export settings"}), 500
|
771
|
-
except Exception as e:
|
772
|
-
logger.error(f"Error exporting settings: {e}")
|
773
|
-
return jsonify({"error": str(e)}), 500
|
774
|
-
|
775
|
-
|
776
568
|
@settings_bp.route("/api/import", methods=["POST"])
|
777
569
|
def api_import_settings():
|
778
|
-
"""Import settings from file"""
|
570
|
+
"""Import settings from defaults file"""
|
779
571
|
try:
|
780
|
-
data = request.get_json() or {}
|
781
|
-
setting_type_str = data.get("type")
|
782
|
-
|
783
572
|
db_session = get_db_session()
|
784
573
|
settings_manager = get_settings_manager(db_session)
|
785
574
|
|
786
|
-
|
787
|
-
if setting_type_str:
|
788
|
-
try:
|
789
|
-
setting_type = SettingType[setting_type_str.upper()]
|
790
|
-
success = settings_manager.import_from_file(setting_type)
|
791
|
-
except KeyError:
|
792
|
-
return (
|
793
|
-
jsonify({"error": f"Invalid setting type: {setting_type_str}"}),
|
794
|
-
400,
|
795
|
-
)
|
796
|
-
else:
|
797
|
-
success = settings_manager.import_from_file()
|
575
|
+
success = settings_manager.load_from_defaults_file()
|
798
576
|
|
799
577
|
if success:
|
800
578
|
return jsonify({"message": "Settings imported successfully"})
|
@@ -1065,131 +843,67 @@ def api_get_available_models():
|
|
1065
843
|
def api_get_available_search_engines():
|
1066
844
|
"""Get available search engines"""
|
1067
845
|
try:
|
1068
|
-
#
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
for key in engines_dict.keys()
|
1088
|
-
]
|
1089
|
-
|
1090
|
-
return jsonify({"engines": engines_dict, "engine_options": engine_options})
|
846
|
+
# Find search engines that are set in the DB.
|
847
|
+
db_session = get_db_session()
|
848
|
+
name_settings = (
|
849
|
+
db_session.query(Setting)
|
850
|
+
.filter(Setting.type == "SEARCH")
|
851
|
+
.filter(Setting.key.startswith("search.engine"))
|
852
|
+
.filter(Setting.key.endswith(".display_name"))
|
853
|
+
).all()
|
854
|
+
|
855
|
+
# These should all correspond to different search engines.
|
856
|
+
engines_dict = {}
|
857
|
+
for setting in name_settings:
|
858
|
+
key_parts = setting.key.split(".")
|
859
|
+
if key_parts[2] == "auto":
|
860
|
+
# The auto engine is not in the web or local category.
|
861
|
+
engine_name = "auto"
|
862
|
+
else:
|
863
|
+
engine_name = setting.key.split(".")[3]
|
864
|
+
display_name = setting.value
|
1091
865
|
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
# Convert to dict with engine name as key and display name as value
|
1100
|
-
engines_dict = {
|
1101
|
-
engine: engine.replace("_", " ").title()
|
1102
|
-
for engine in search_engines
|
1103
|
-
}
|
866
|
+
description = (
|
867
|
+
db_session.query(Setting)
|
868
|
+
.filter(Setting.key == f"search.engine.web.{engine_name}.description")
|
869
|
+
.first()
|
870
|
+
)
|
871
|
+
if description is None:
|
872
|
+
description = ""
|
1104
873
|
else:
|
1105
|
-
|
874
|
+
description = description.value
|
1106
875
|
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
876
|
+
strengths = (
|
877
|
+
db_session.query(Setting)
|
878
|
+
.filter(Setting.key == f"search.engine.web.{engine_name}.strengths")
|
879
|
+
.first()
|
880
|
+
)
|
881
|
+
if strengths is None:
|
882
|
+
# No strengths in DB.
|
883
|
+
strengths = []
|
884
|
+
else:
|
885
|
+
strengths = strengths.value
|
1110
886
|
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
"value": key,
|
1115
|
-
"label": (
|
1116
|
-
value
|
1117
|
-
if isinstance(value, str)
|
1118
|
-
else key.replace("_", " ").title()
|
1119
|
-
),
|
1120
|
-
}
|
1121
|
-
for key, value in engines_dict.items()
|
1122
|
-
]
|
887
|
+
engines_dict[engine_name] = dict(
|
888
|
+
display_name=display_name, strengths=strengths, description=description
|
889
|
+
)
|
1123
890
|
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
# Use hardcoded defaults from search_engines.toml
|
1130
|
-
defaults = {
|
1131
|
-
"wikipedia": "Wikipedia",
|
1132
|
-
"arxiv": "ArXiv Papers",
|
1133
|
-
"pubmed": "PubMed Medical",
|
1134
|
-
"github": "GitHub Code",
|
1135
|
-
"searxng": "SearXNG (Self-hosted)",
|
1136
|
-
"serpapi": "SerpAPI (Google)",
|
1137
|
-
"google_pse": "Google PSE",
|
1138
|
-
"auto": "Auto-select",
|
891
|
+
# Format as options for dropdown
|
892
|
+
engine_options = [
|
893
|
+
{
|
894
|
+
"value": key,
|
895
|
+
"label": engines_dict.get(key, {}).get("display_name", key),
|
1139
896
|
}
|
897
|
+
for key in engines_dict.keys()
|
898
|
+
]
|
1140
899
|
|
1141
|
-
|
1142
|
-
{"value": key, "label": value} for key, value in defaults.items()
|
1143
|
-
]
|
900
|
+
return jsonify({"engines": engines_dict, "engine_options": engine_options})
|
1144
901
|
|
1145
|
-
return jsonify({"engines": defaults, "engine_options": engine_options})
|
1146
902
|
except Exception as e:
|
1147
903
|
logger.error(f"Error getting available search engines: {e}")
|
1148
904
|
return jsonify({"error": str(e)}), 500
|
1149
905
|
|
1150
906
|
|
1151
|
-
def get_engines_from_file():
|
1152
|
-
"""Get available search engines directly from the toml file"""
|
1153
|
-
try:
|
1154
|
-
# Try to load from the actual config directory
|
1155
|
-
config_dir = get_config_dir()
|
1156
|
-
search_engines_file = config_dir / "config" / "search_engines.toml"
|
1157
|
-
|
1158
|
-
# If file doesn't exist in user config, try the defaults
|
1159
|
-
if not search_engines_file.exists():
|
1160
|
-
# Look in the defaults folder instead
|
1161
|
-
import inspect
|
1162
|
-
|
1163
|
-
from ...defaults import search_engines
|
1164
|
-
|
1165
|
-
# Get the path to the search_engines.toml file
|
1166
|
-
module_path = inspect.getfile(search_engines)
|
1167
|
-
default_file = Path(module_path)
|
1168
|
-
|
1169
|
-
if default_file.exists() and default_file.suffix == ".toml":
|
1170
|
-
search_engines_file = default_file
|
1171
|
-
|
1172
|
-
# If we found a file, load it
|
1173
|
-
if search_engines_file.exists():
|
1174
|
-
data = toml.load(search_engines_file)
|
1175
|
-
|
1176
|
-
# Filter out the metadata entries (like DEFAULT_SEARCH_ENGINE)
|
1177
|
-
engines = {k: v for k, v in data.items() if isinstance(v, dict)}
|
1178
|
-
|
1179
|
-
# Add display names for each engine
|
1180
|
-
for key, engine in engines.items():
|
1181
|
-
if "display_name" not in engine:
|
1182
|
-
# Create a display name from the key
|
1183
|
-
engine["display_name"] = key.replace("_", " ").title()
|
1184
|
-
|
1185
|
-
return engines
|
1186
|
-
|
1187
|
-
return None
|
1188
|
-
except Exception as e:
|
1189
|
-
logger.error(f"Error loading search engines from file: {e}")
|
1190
|
-
return None
|
1191
|
-
|
1192
|
-
|
1193
907
|
# Legacy routes for backward compatibility - these will redirect to the new routes
|
1194
908
|
@settings_bp.route("/main", methods=["GET"])
|
1195
909
|
def main_config_page():
|
@@ -1334,7 +1048,6 @@ def fix_corrupted_settings():
|
|
1334
1048
|
|
1335
1049
|
# Search settings
|
1336
1050
|
for key in [
|
1337
|
-
"app.research_iterations",
|
1338
1051
|
"app.questions_per_iteration",
|
1339
1052
|
"app.search_engine",
|
1340
1053
|
"app.iterations",
|
@@ -1472,8 +1185,6 @@ def fix_corrupted_settings():
|
|
1472
1185
|
default_value = 10
|
1473
1186
|
elif setting.key == "search.region":
|
1474
1187
|
default_value = "us"
|
1475
|
-
elif setting.key == "search.research_iterations":
|
1476
|
-
default_value = 2
|
1477
1188
|
elif setting.key == "search.questions_per_iteration":
|
1478
1189
|
default_value = 3
|
1479
1190
|
elif setting.key == "search.searches_per_section":
|
@@ -259,53 +259,53 @@ def run_research_process(
|
|
259
259
|
f"Overriding system settings with: provider={model_provider}, model={model}, search_engine={search_engine}"
|
260
260
|
)
|
261
261
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
262
|
+
# Override LLM if model or model_provider specified
|
263
|
+
if model or model_provider:
|
264
|
+
try:
|
265
|
+
# Get LLM with the overridden settings
|
266
|
+
# Explicitly create the model with parameters to avoid fallback issues
|
267
|
+
use_llm = get_llm(
|
268
|
+
model_name=model,
|
269
|
+
provider=model_provider,
|
270
|
+
openai_endpoint_url=custom_endpoint,
|
271
|
+
)
|
272
272
|
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
273
|
+
logger.info(
|
274
|
+
"Successfully set LLM to: provider=%s, model=%s",
|
275
|
+
model_provider,
|
276
|
+
model,
|
277
|
+
)
|
278
|
+
except Exception as e:
|
279
|
+
logger.error(
|
280
|
+
"Error setting LLM provider=%s, model=%s: %s",
|
281
|
+
model_provider,
|
282
|
+
model,
|
283
|
+
str(e),
|
284
|
+
)
|
285
|
+
logger.error(traceback.format_exc())
|
286
286
|
|
287
|
-
|
288
|
-
|
289
|
-
|
287
|
+
# Set the progress callback in the system
|
288
|
+
system = AdvancedSearchSystem(llm=use_llm)
|
289
|
+
system.set_progress_callback(progress_callback)
|
290
290
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
291
|
+
# Override search engine if specified
|
292
|
+
if search_engine:
|
293
|
+
try:
|
294
|
+
if iterations:
|
295
|
+
system.max_iterations = int(iterations)
|
296
|
+
if questions_per_iteration:
|
297
|
+
system.questions_per_iteration = int(questions_per_iteration)
|
298
|
+
|
299
|
+
# Create a new search object with these settings
|
300
|
+
system.search = get_search(
|
301
|
+
search_tool=search_engine, llm_instance=system.model
|
302
|
+
)
|
303
303
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
304
|
+
logger.info("Successfully set search engine to: %s", search_engine)
|
305
|
+
except Exception as e:
|
306
|
+
logger.error(
|
307
|
+
"Error setting search engine to %s: %s", search_engine, str(e)
|
308
|
+
)
|
309
309
|
|
310
310
|
# Run the search
|
311
311
|
progress_callback("Starting research process", 5, {"phase": "init"})
|