local-deep-research 0.4.1__py3-none-any.whl → 0.4.3__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.
@@ -1 +1 @@
1
- __version__ = "0.4.1"
1
+ __version__ = "0.4.3"
@@ -79,7 +79,7 @@ def get_llm(model_name=None, temperature=None, provider=None, openai_endpoint_ur
79
79
  if get_db_setting("llm.supports_max_tokens", True):
80
80
  # Use 80% of context window to leave room for prompts
81
81
  max_tokens = min(
82
- get_db_setting("llm.max_tokens", 30000), int(context_window_size * 0.8)
82
+ int(get_db_setting("llm.max_tokens", 30000)), int(context_window_size * 0.8)
83
83
  )
84
84
  common_params["max_tokens"] = max_tokens
85
85
 
@@ -342,7 +342,7 @@
342
342
  "options": null,
343
343
  "step": 0.05,
344
344
  "type": "LLM",
345
- "ui_element": "slider",
345
+ "ui_element": "range",
346
346
  "value": 0.7,
347
347
  "visible": true
348
348
  },
@@ -1,10 +1,10 @@
1
1
  import importlib.resources as pkg_resources
2
2
  import json
3
3
  import os
4
- from typing import Any, Dict, Optional, Union
4
+ from typing import Any, Dict, Optional, Type, Union
5
5
 
6
6
  from loguru import logger
7
- from sqlalchemy import func
7
+ from sqlalchemy import func, or_
8
8
  from sqlalchemy.exc import SQLAlchemyError
9
9
  from sqlalchemy.orm import Session
10
10
 
@@ -45,6 +45,15 @@ class SettingsManager:
45
45
  Provides methods to get and set settings, with the ability to override settings in memory.
46
46
  """
47
47
 
48
+ _UI_ELEMENT_TO_SETTING_TYPE = {
49
+ "text": str,
50
+ "password": str,
51
+ "select": str,
52
+ "number": float,
53
+ "range": float,
54
+ "checkbox": bool,
55
+ }
56
+
48
57
  def __init__(self, db_session: Session):
49
58
  """
50
59
  Initialize the settings manager
@@ -59,6 +68,57 @@ class SettingsManager:
59
68
  default_settings = pkg_resources.read_text(defaults, "default_settings.json")
60
69
  self.default_settings = json.loads(default_settings)
61
70
 
71
+ def __get_typed_setting_value(
72
+ self, setting: Type[Setting], default: Any = None, check_env: bool = True
73
+ ) -> str | float | bool | None:
74
+ """
75
+ Extracts the value for a particular setting, ensuring that it has the
76
+ correct type.
77
+
78
+ Args:
79
+ setting: The setting to get the value for.
80
+ default: Default value to return if the value of the setting is
81
+ invalid.
82
+ check_env: If true, it will check the environment variable for
83
+ this setting before reading from the DB.
84
+
85
+ Returns:
86
+ The value of the setting.
87
+
88
+ """
89
+ setting_type = self._UI_ELEMENT_TO_SETTING_TYPE.get(setting.ui_element, None)
90
+ if setting_type is None:
91
+ logger.warning(
92
+ "Got unknown type {} for setting {}, returning default value.",
93
+ setting.ui_element,
94
+ setting.key,
95
+ )
96
+ return default
97
+
98
+ # Check environment variable first, then database.
99
+ if check_env:
100
+ env_value = check_env_setting(setting.key)
101
+ if env_value is not None:
102
+ try:
103
+ return setting_type(env_value)
104
+ except ValueError:
105
+ logger.warning(
106
+ "Setting {} has invalid value {}. Falling back to DB.",
107
+ setting.key,
108
+ env_value,
109
+ )
110
+
111
+ # If environment variable does not exist, read from the database.
112
+ try:
113
+ return setting_type(setting.value)
114
+ except ValueError:
115
+ logger.warning(
116
+ "Setting {} has invalid value {}. Returning default.",
117
+ setting.key,
118
+ setting.value,
119
+ )
120
+ return default
121
+
62
122
  def get_setting(self, key: str, default: Any = None, check_env: bool = True) -> Any:
63
123
  """
64
124
  Get a setting value
@@ -72,37 +132,29 @@ class SettingsManager:
72
132
  Returns:
73
133
  Setting value or default if not found
74
134
  """
75
- if check_env:
76
- env_value = check_env_setting(key)
77
- if env_value is not None:
78
- return env_value
79
-
80
135
  # If using database first approach and session available, check database
81
136
  if self.db_first and self.db_session:
82
137
  try:
83
138
  settings = (
84
139
  self.db_session.query(Setting)
85
140
  # This will find exact matches and any subkeys.
86
- .filter(Setting.key.startswith(key)).all()
141
+ .filter(
142
+ or_(Setting.key == key, Setting.key.startswith(f"{key}."))
143
+ ).all()
87
144
  )
88
145
  if len(settings) == 1:
89
146
  # This is a bottom-level key.
90
- value = settings[0].value
91
- return value
147
+ return self.__get_typed_setting_value(
148
+ settings[0], default, check_env
149
+ )
92
150
  elif len(settings) > 1:
93
151
  # This is a higher-level key.
94
152
  settings_map = {}
95
153
  for setting in settings:
96
154
  output_key = setting.key.removeprefix(f"{key}.")
97
- value = setting.value
98
-
99
- if check_env:
100
- # Handle possible replacements from environment variables.
101
- env_value = check_env_setting(setting.key)
102
- if env_value is not None:
103
- value = env_value
104
-
105
- settings_map[output_key] = value
155
+ settings_map[output_key] = self.__get_typed_setting_value(
156
+ setting, default, check_env
157
+ )
106
158
  return settings_map
107
159
  except SQLAlchemyError as e:
108
160
  logger.error(f"Error retrieving setting {key} from database: {e}")
@@ -149,6 +201,7 @@ class SettingsManager:
149
201
  value=value,
150
202
  type=setting_type,
151
203
  name=key.split(".")[-1].replace("_", " ").title(),
204
+ ui_element="text",
152
205
  description=f"Setting for {key}",
153
206
  )
154
207
  self.db_session.add(new_setting)
@@ -98,7 +98,7 @@ class SearXNGSearchEngine(BaseSearchEngine):
98
98
  self.language = language
99
99
  try:
100
100
  self.safe_search = SafeSearchSetting[safe_search]
101
- except ValueError:
101
+ except KeyError:
102
102
  logger.error(
103
103
  "'{}' is not a valid safe search setting. Disabling safe search",
104
104
  safe_search,
@@ -4,20 +4,12 @@ Loads search engine definitions from the user's configuration.
4
4
  """
5
5
 
6
6
  import json
7
-
8
- import logging
9
- from typing import Any, Dict, List
10
-
11
- from ..utilities.db_utils import get_db_setting
12
- from .default_search_engines import get_default_elasticsearch_config
13
-
14
- from functools import cache
15
7
  from typing import Any, Dict, List
16
8
 
17
9
  from loguru import logger
18
10
 
19
-
20
11
  from ..utilities.db_utils import get_db_setting
12
+ from .default_search_engines import get_default_elasticsearch_config
21
13
 
22
14
 
23
15
  def _extract_per_engine_config(raw_config: Dict[str, Any]) -> Dict[str, Dict[str, Any]]:
@@ -69,7 +61,7 @@ def search_config() -> Dict[str, Any]:
69
61
  # Add alias for 'auto' if it exists
70
62
  if "auto" in search_engines and "meta" not in search_engines:
71
63
  search_engines["meta"] = search_engines["auto"]
72
-
64
+
73
65
  # Add Elasticsearch search engine if not already present
74
66
  if "elasticsearch" not in search_engines:
75
67
  logger.info("Adding default Elasticsearch search engine configuration")
@@ -91,7 +83,7 @@ def search_config() -> Dict[str, Any]:
91
83
  config["paths"] = json.loads(config["paths"])
92
84
  except json.decoder.JSONDecodeError:
93
85
  logger.error(
94
- f"Invalid paths specified for local collection: "
86
+ f"Path for local collection '{collection}' is not a valid JSON array: "
95
87
  f"{config['paths']}"
96
88
  )
97
89
  config["paths"] = []
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: local-deep-research
3
- Version: 0.4.1
3
+ Version: 0.4.3
4
4
  Summary: AI-powered research assistant with deep, iterative analysis using LLMs and web searches
5
5
  Author-Email: LearningCircuit <185559241+LearningCircuit@users.noreply.github.com>, HashedViking <6432677+HashedViking@users.noreply.github.com>
6
6
  License: MIT License
@@ -1,9 +1,9 @@
1
- local_deep_research-0.4.1.dist-info/METADATA,sha256=qKbtKkvdX52q25NBq4-O4d7d74fjYmM5GyPxuB4TIRc,17352
2
- local_deep_research-0.4.1.dist-info/WHEEL,sha256=tSfRZzRHthuv7vxpI4aehrdN9scLjk-dCJkPLzkHxGg,90
3
- local_deep_research-0.4.1.dist-info/entry_points.txt,sha256=GcXS501Rjh-P80S8db7hnrQ23mS_Jg27PwpVQVO77as,113
4
- local_deep_research-0.4.1.dist-info/licenses/LICENSE,sha256=Qg2CaTdu6SWnSqk1_JtgBPp_Da-LdqJDhT1Vt1MUc5s,1072
1
+ local_deep_research-0.4.3.dist-info/METADATA,sha256=8xlBwQ1wxZeZkbPKoHikLxTfWk2fkRoGdkCgX4e50l8,17352
2
+ local_deep_research-0.4.3.dist-info/WHEEL,sha256=tSfRZzRHthuv7vxpI4aehrdN9scLjk-dCJkPLzkHxGg,90
3
+ local_deep_research-0.4.3.dist-info/entry_points.txt,sha256=GcXS501Rjh-P80S8db7hnrQ23mS_Jg27PwpVQVO77as,113
4
+ local_deep_research-0.4.3.dist-info/licenses/LICENSE,sha256=Qg2CaTdu6SWnSqk1_JtgBPp_Da-LdqJDhT1Vt1MUc5s,1072
5
5
  local_deep_research/__init__.py,sha256=BPWOE6L1vBgBshHlyzrrp0gYo6uR3ljiNBFDRK_3aIw,911
6
- local_deep_research/__version__.py,sha256=pMtTmSUht-XtbR_7Doz6bsQqopJJd8rZ8I8zy2HwwoA,22
6
+ local_deep_research/__version__.py,sha256=Nyg0pmk5ea9-SLCAFEIF96ByFx4-TJFtrqYPN-Zn6g4,22
7
7
  local_deep_research/advanced_search_system/__init__.py,sha256=sGusMj4eFIrhXR6QbOM16UDKB6aI-iS4IFivKWpMlh0,234
8
8
  local_deep_research/advanced_search_system/filters/__init__.py,sha256=2dXrV4skcVHI2Lb3BSL2Ajq0rnLeSw7kc1MbIynMxa4,190
9
9
  local_deep_research/advanced_search_system/filters/base_filter.py,sha256=58Ux0ppXafL8Vy2qbWioUBMqGtK1dgtSF5A68BP8M8Y,1010
@@ -72,11 +72,11 @@ local_deep_research/benchmarks/runners.py,sha256=ktdEYgoVoQtToCJSKPMB7rF2fOzimFR
72
72
  local_deep_research/benchmarks/templates.py,sha256=ooRYTbFmSQCKxHVuXAYofTDTXAQ9yDaAUtKGqRaHy2E,2276
73
73
  local_deep_research/citation_handler.py,sha256=MZVd6xl7g3xrWauFBPuVIC36z8onc-zQb8xI4dQXxsU,4307
74
74
  local_deep_research/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
- local_deep_research/config/llm_config.py,sha256=Y-56Bc05Kglh1jxTwa1xVLso7YBUGJqQHq3y_R-un34,16022
75
+ local_deep_research/config/llm_config.py,sha256=31F-nlloP_N30HYZqnJ2sCNMZXlJVB9AMwz99UctHi4,16027
76
76
  local_deep_research/config/search_config.py,sha256=-m4BkHHMvzNkIuZmximmE3T5_H-JU4UZubEc_cDpWH0,2130
77
77
  local_deep_research/defaults/.env.template,sha256=_eVCy4d_XwpGXy8n50CG3wH9xx2oqJCFKS7IbqgInDk,491
78
78
  local_deep_research/defaults/__init__.py,sha256=C_0t0uZmtrVB4rM9NM9Wx8PJU5kFcT-qOHvws5W2iOg,1352
79
- local_deep_research/defaults/default_settings.json,sha256=k5H2pRXiOb0OeCfmgFKZqS9Rh3myjtHZDbnVNdDXxnQ,124257
79
+ local_deep_research/defaults/default_settings.json,sha256=UTzWrOONlvR6UELT7remAN5qLLMLYvjnQXNMd0cH87w,124256
80
80
  local_deep_research/migrate_db.py,sha256=S1h6Bv0OJdRW4BaH7MIMrUXBRV_yqgH2T6LVOZKTQjI,4634
81
81
  local_deep_research/report_generator.py,sha256=-G3KDEbsuU3PdxDfuo5v28DIX7RE1yJCCBU2KgRbNzI,9084
82
82
  local_deep_research/search_system.py,sha256=DCBSLSUyLqPuHrgOuTlDizT_cnWRBICYKH-haMWWoDo,8412
@@ -108,7 +108,7 @@ local_deep_research/web/routes/research_routes.py,sha256=RkuT6VA5BlKzfeFzp3HvoEQ
108
108
  local_deep_research/web/routes/settings_routes.py,sha256=Yt4xVt6XcGPSEFuAkcQ4zlZ2r5dIbV3VNsWIXoGeflw,58606
109
109
  local_deep_research/web/services/research_service.py,sha256=kHdonXtGDTSU2_jBlCP_deqMdydhxA_p7EabsR5kBkE,38812
110
110
  local_deep_research/web/services/resource_service.py,sha256=yKgOC6GEOmHqRoGzwf52e19UaGCCS1DbDbOIXgWGvGc,4378
111
- local_deep_research/web/services/settings_manager.py,sha256=Emo_QRnjVwi8HHT8N79io3SOUxPf_VwwwOHTTvJ1C-c,17238
111
+ local_deep_research/web/services/settings_manager.py,sha256=FKW8LKVsBGr_vgWHn1lZZRwiqRQ98ZrNicLOwf6vjPw,19058
112
112
  local_deep_research/web/services/settings_service.py,sha256=-ZG78JR14GuhsaXIF4OQOqfRfrw2QIqYEKwTOFhsuFo,3497
113
113
  local_deep_research/web/services/socket_service.py,sha256=jZGXk6kesBOf4bAdLiT3V4Ofod12pGKTsvxr3ml8ydY,7272
114
114
  local_deep_research/web/static/css/custom_dropdown.css,sha256=-pCx6oazWVgwqFAGq_eZ8OrTKMVQlgkKYCM6w-bACLs,7949
@@ -166,12 +166,12 @@ local_deep_research/web_search_engines/engines/search_engine_guardian.py,sha256=
166
166
  local_deep_research/web_search_engines/engines/search_engine_local.py,sha256=RJEXb6wTPgTfQoOyuLYLZwqx0JU7yukehHiu4C0Zel4,41221
167
167
  local_deep_research/web_search_engines/engines/search_engine_local_all.py,sha256=8hAYhacU15Vi13pjo0LRVt2tI5SqcONDwYwvdtg1HyY,5620
168
168
  local_deep_research/web_search_engines/engines/search_engine_pubmed.py,sha256=O99qfbSz7RHqinAP_C0iod-ZaEGE5tyBbh1DJi2-VhQ,38495
169
- local_deep_research/web_search_engines/engines/search_engine_searxng.py,sha256=amEK2ljX-6QtJPBUB9fS0bE48Q8SmYInO2LaSq_x-Rw,17867
169
+ local_deep_research/web_search_engines/engines/search_engine_searxng.py,sha256=gS-GjjLzjZvlaQB-E0u-IADzJmLRGZaLmNQ7DpdqMw4,17865
170
170
  local_deep_research/web_search_engines/engines/search_engine_semantic_scholar.py,sha256=jYs_TRM0izMfldsZ8NkCQsP-o6vCPXUjyxt0nIsxOVI,22799
171
171
  local_deep_research/web_search_engines/engines/search_engine_serpapi.py,sha256=_afKJVFV0xpdrO3vL71aORMIGmbe0y8o7Ly0_xXryDQ,8920
172
172
  local_deep_research/web_search_engines/engines/search_engine_wayback.py,sha256=rfRs7WJxa-H1DXSyduFHBMfpFwWEVRXLd8s_78iU8gU,17894
173
173
  local_deep_research/web_search_engines/engines/search_engine_wikipedia.py,sha256=UxYBSGD-XZGQantq_AdgtBA8FCKV0C6mEr6GS_vleQQ,10092
174
174
  local_deep_research/web_search_engines/search_engine_base.py,sha256=TFmkIGgzIkXFsk9jhGn2PYyxveOWzKQLrhpZy5qaggE,10803
175
175
  local_deep_research/web_search_engines/search_engine_factory.py,sha256=73lwSenv7tK7eGIBOPh13hPdn0oZ9FC0EMjZx5YRPg4,11865
176
- local_deep_research/web_search_engines/search_engines_config.py,sha256=bRly8zsoXvlQIovbVChnkhj4AsGJMzFlEiArrmsblrE,5375
177
- local_deep_research-0.4.1.dist-info/RECORD,,
176
+ local_deep_research/web_search_engines/search_engines_config.py,sha256=qfmrTZjjVeMfdZQ9WIAEWKdPPEtZhTAJ5KjCdgsz_ww,5259
177
+ local_deep_research-0.4.3.dist-info/RECORD,,