local-deep-research 0.2.3__py3-none-any.whl → 0.3.1__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.
Files changed (42) hide show
  1. local_deep_research/__init__.py +1 -1
  2. local_deep_research/__version__.py +1 -0
  3. local_deep_research/advanced_search_system/filters/cross_engine_filter.py +5 -1
  4. local_deep_research/advanced_search_system/strategies/base_strategy.py +5 -2
  5. local_deep_research/advanced_search_system/strategies/iterdrag_strategy.py +23 -16
  6. local_deep_research/advanced_search_system/strategies/parallel_search_strategy.py +13 -6
  7. local_deep_research/advanced_search_system/strategies/rapid_search_strategy.py +4 -3
  8. local_deep_research/advanced_search_system/strategies/source_based_strategy.py +57 -62
  9. local_deep_research/advanced_search_system/strategies/standard_strategy.py +8 -4
  10. local_deep_research/api/research_functions.py +0 -46
  11. local_deep_research/citation_handler.py +2 -5
  12. local_deep_research/config/llm_config.py +25 -68
  13. local_deep_research/config/search_config.py +8 -21
  14. local_deep_research/defaults/default_settings.json +3996 -0
  15. local_deep_research/search_system.py +34 -31
  16. local_deep_research/utilities/db_utils.py +22 -3
  17. local_deep_research/utilities/search_utilities.py +10 -7
  18. local_deep_research/web/app.py +3 -23
  19. local_deep_research/web/app_factory.py +1 -25
  20. local_deep_research/web/database/migrations.py +20 -418
  21. local_deep_research/web/routes/settings_routes.py +75 -364
  22. local_deep_research/web/services/research_service.py +43 -43
  23. local_deep_research/web/services/settings_manager.py +108 -315
  24. local_deep_research/web/services/settings_service.py +3 -56
  25. local_deep_research/web/static/js/components/research.js +1 -1
  26. local_deep_research/web/static/js/components/settings.js +16 -4
  27. local_deep_research/web/static/js/research_form.js +106 -0
  28. local_deep_research/web/templates/pages/research.html +3 -2
  29. local_deep_research/web_search_engines/engines/meta_search_engine.py +56 -21
  30. local_deep_research/web_search_engines/engines/search_engine_local.py +11 -2
  31. local_deep_research/web_search_engines/engines/search_engine_local_all.py +7 -11
  32. local_deep_research/web_search_engines/search_engine_factory.py +12 -64
  33. local_deep_research/web_search_engines/search_engines_config.py +123 -64
  34. {local_deep_research-0.2.3.dist-info → local_deep_research-0.3.1.dist-info}/METADATA +16 -1
  35. {local_deep_research-0.2.3.dist-info → local_deep_research-0.3.1.dist-info}/RECORD +38 -39
  36. local_deep_research/config/config_files.py +0 -245
  37. local_deep_research/defaults/local_collections.toml +0 -53
  38. local_deep_research/defaults/main.toml +0 -80
  39. local_deep_research/defaults/search_engines.toml +0 -291
  40. {local_deep_research-0.2.3.dist-info → local_deep_research-0.3.1.dist-info}/WHEEL +0 -0
  41. {local_deep_research-0.2.3.dist-info → local_deep_research-0.3.1.dist-info}/entry_points.txt +0 -0
  42. {local_deep_research-0.2.3.dist-info → local_deep_research-0.3.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,8 +1,6 @@
1
1
  import logging
2
2
  import os
3
- from pathlib import Path
4
3
 
5
- from dynaconf.vendor.box.exceptions import BoxKeyError
6
4
  from langchain_anthropic import ChatAnthropic
7
5
  from langchain_community.llms import VLLM
8
6
  from langchain_ollama import ChatOllama
@@ -10,7 +8,6 @@ from langchain_openai import ChatOpenAI
10
8
 
11
9
  from ..utilities.db_utils import get_db_setting
12
10
  from ..utilities.search_utilities import remove_think_tags
13
- from .config_files import CONFIG_DIR, settings
14
11
 
15
12
  # Setup logging
16
13
  logger = logging.getLogger(__name__)
@@ -26,7 +23,6 @@ VALID_PROVIDERS = [
26
23
  "llamacpp",
27
24
  "none",
28
25
  ]
29
- SECRETS_FILE = CONFIG_DIR / ".secrets.toml"
30
26
 
31
27
 
32
28
  def get_llm(model_name=None, temperature=None, provider=None, openai_endpoint_url=None):
@@ -46,11 +42,11 @@ def get_llm(model_name=None, temperature=None, provider=None, openai_endpoint_ur
46
42
 
47
43
  # Use database values for parameters if not provided
48
44
  if model_name is None:
49
- model_name = get_db_setting("llm.model", settings.llm.model)
45
+ model_name = get_db_setting("llm.model", "gemma:latest")
50
46
  if temperature is None:
51
- temperature = get_db_setting("llm.temperature", settings.llm.temperature)
47
+ temperature = get_db_setting("llm.temperature", 0.7)
52
48
  if provider is None:
53
- provider = get_db_setting("llm.provider", settings.llm.provider)
49
+ provider = get_db_setting("llm.provider", "ollama")
54
50
 
55
51
  # Clean model name: remove quotes and extra whitespace
56
52
  if model_name:
@@ -77,21 +73,12 @@ def get_llm(model_name=None, temperature=None, provider=None, openai_endpoint_ur
77
73
  common_params = {
78
74
  "temperature": temperature,
79
75
  }
80
- try:
81
- common_params["max_tokens"] = settings.llm.max_tokens
82
- except BoxKeyError:
83
- # Some providers don't support this parameter, in which case it can
84
- # be omitted.
85
- pass
76
+ if get_db_setting("llm.supports_max_tokens", True):
77
+ common_params["max_tokens"] = get_db_setting("llm.max_tokens", 30000)
86
78
 
87
79
  # Handle different providers
88
80
  if provider == "anthropic":
89
- api_key_name = "ANTHROPIC_API_KEY"
90
- api_key = settings.get(api_key_name, "")
91
- if not api_key:
92
- api_key = os.getenv(api_key_name)
93
- if not api_key:
94
- api_key = os.getenv("LDR_" + api_key_name)
81
+ api_key = get_db_setting("llm.anthropic.api_key")
95
82
  if not api_key:
96
83
  logger.warning(
97
84
  "ANTHROPIC_API_KEY not found. Falling back to default model."
@@ -104,12 +91,7 @@ def get_llm(model_name=None, temperature=None, provider=None, openai_endpoint_ur
104
91
  return wrap_llm_without_think_tags(llm)
105
92
 
106
93
  elif provider == "openai":
107
- api_key_name = "OPENAI_API_KEY"
108
- api_key = settings.get(api_key_name, "")
109
- if not api_key:
110
- api_key = os.getenv(api_key_name)
111
- if not api_key:
112
- api_key = os.getenv("LDR_" + api_key_name)
94
+ api_key = get_db_setting("llm.openai.api_key")
113
95
  if not api_key:
114
96
  logger.warning("OPENAI_API_KEY not found. Falling back to default model.")
115
97
  return get_fallback_model(temperature)
@@ -118,12 +100,7 @@ def get_llm(model_name=None, temperature=None, provider=None, openai_endpoint_ur
118
100
  return wrap_llm_without_think_tags(llm)
119
101
 
120
102
  elif provider == "openai_endpoint":
121
- api_key_name = "OPENAI_ENDPOINT_API_KEY"
122
- api_key = settings.get(api_key_name, "")
123
- if not api_key:
124
- api_key = os.getenv(api_key_name)
125
- if not api_key:
126
- api_key = os.getenv("LDR_" + api_key_name)
103
+ api_key = get_db_setting("llm.openai_endpoint.api_key")
127
104
  if not api_key:
128
105
  logger.warning(
129
106
  "OPENAI_ENDPOINT_API_KEY not found. Falling back to default model."
@@ -131,9 +108,9 @@ def get_llm(model_name=None, temperature=None, provider=None, openai_endpoint_ur
131
108
  return get_fallback_model(temperature)
132
109
 
133
110
  # Get endpoint URL from settings
134
- if openai_endpoint_url is not None:
111
+ if openai_endpoint_url is None:
135
112
  openai_endpoint_url = get_db_setting(
136
- "llm.openai_endpoint_url", settings.llm.openai_endpoint_url
113
+ "llm.openai_endpoint.url", "https://openrouter.ai/api/v1"
137
114
  )
138
115
 
139
116
  llm = ChatOpenAI(
@@ -163,10 +140,7 @@ def get_llm(model_name=None, temperature=None, provider=None, openai_endpoint_ur
163
140
  elif provider == "ollama":
164
141
  try:
165
142
  # Use the configurable Ollama base URL
166
- base_url = os.getenv(
167
- "OLLAMA_BASE_URL",
168
- settings.llm.get("ollama_base_url", "http://localhost:11434"),
169
- )
143
+ base_url = get_db_setting("llm.ollama.url", "http://localhost:11434")
170
144
 
171
145
  # Check if Ollama is available before trying to use it
172
146
  if not is_ollama_available():
@@ -230,15 +204,14 @@ def get_llm(model_name=None, temperature=None, provider=None, openai_endpoint_ur
230
204
 
231
205
  elif provider == "lmstudio":
232
206
  # LM Studio supports OpenAI API format, so we can use ChatOpenAI directly
233
- lmstudio_url = settings.llm.get("lmstudio_url", "http://localhost:1234")
234
- lmstudio_url = get_db_setting("llm.lmstudio_url", lmstudio_url)
207
+ lmstudio_url = get_db_setting("llm.lmstudio.url", "http://localhost:1234")
235
208
 
236
209
  llm = ChatOpenAI(
237
210
  model=model_name,
238
211
  api_key="lm-studio", # LM Studio doesn't require a real API key
239
212
  base_url=f"{lmstudio_url}/v1", # Use the configured URL with /v1 endpoint
240
213
  temperature=temperature,
241
- max_tokens=get_db_setting("llm.max_tokens", settings.llm.max_tokens),
214
+ max_tokens=get_db_setting("llm.max_tokens", 30000),
242
215
  )
243
216
  return wrap_llm_without_think_tags(llm)
244
217
 
@@ -247,25 +220,21 @@ def get_llm(model_name=None, temperature=None, provider=None, openai_endpoint_ur
247
220
  from langchain_community.llms import LlamaCpp
248
221
 
249
222
  # Get LlamaCpp model path from settings
250
- model_path = settings.llm.get("llamacpp_model_path", "")
251
- model_path = get_db_setting("llm.llamacpp_model_path", model_path)
223
+ model_path = get_db_setting("llm.llamacpp_model_path")
252
224
  if not model_path:
253
225
  logger.error("llamacpp_model_path not set in settings")
254
226
  raise ValueError("llamacpp_model_path not set in settings")
255
227
 
256
228
  # Get additional LlamaCpp parameters
257
- n_gpu_layers = settings.llm.get("llamacpp_n_gpu_layers", 1)
258
- n_gpu_layers = get_db_setting("llm.llamacpp_n_gpu_layers", n_gpu_layers)
259
- n_batch = settings.llm.get("llamacpp_n_batch", 512)
260
- n_batch = get_db_setting("llm.llamacpp_n_batch", n_batch)
261
- f16_kv = settings.llm.get("llamacpp_f16_kv", True)
262
- f16_kv = get_db_setting("llm.llamacpp_f16_kv", f16_kv)
229
+ n_gpu_layers = get_db_setting("llm.llamacpp_n_gpu_layers", 1)
230
+ n_batch = get_db_setting("llm.llamacpp_n_batch", 512)
231
+ f16_kv = get_db_setting("llm.llamacpp_f16_kv", True)
263
232
 
264
233
  # Create LlamaCpp instance
265
234
  llm = LlamaCpp(
266
235
  model_path=model_path,
267
236
  temperature=temperature,
268
- max_tokens=get_db_setting("llm.max_tokens", settings.llm.max_tokens),
237
+ max_tokens=get_db_setting("llm.max_tokens", 30000),
269
238
  n_gpu_layers=n_gpu_layers,
270
239
  n_batch=n_batch,
271
240
  f16_kv=f16_kv,
@@ -354,9 +323,7 @@ def get_available_provider_types():
354
323
  def is_openai_available():
355
324
  """Check if OpenAI is available"""
356
325
  try:
357
- api_key = settings.get("OPENAI_API_KEY", "")
358
- if not api_key:
359
- api_key = os.getenv("OPENAI_API_KEY")
326
+ api_key = get_db_setting("llm.openai.api_key")
360
327
  return bool(api_key)
361
328
  except Exception:
362
329
  return False
@@ -365,9 +332,7 @@ def is_openai_available():
365
332
  def is_anthropic_available():
366
333
  """Check if Anthropic is available"""
367
334
  try:
368
- api_key = settings.get("ANTHROPIC_API_KEY", "")
369
- if not api_key:
370
- api_key = os.getenv("ANTHROPIC_API_KEY")
335
+ api_key = get_db_setting("llm.anthropic.api_key")
371
336
  return bool(api_key)
372
337
  except Exception:
373
338
  return False
@@ -376,9 +341,7 @@ def is_anthropic_available():
376
341
  def is_openai_endpoint_available():
377
342
  """Check if OpenAI endpoint is available"""
378
343
  try:
379
- api_key = settings.get("OPENAI_ENDPOINT_API_KEY", "")
380
- if not api_key:
381
- api_key = os.getenv("OPENAI_ENDPOINT_API_KEY")
344
+ api_key = get_db_setting("llm.openai_endpoint.api_key")
382
345
  return bool(api_key)
383
346
  except Exception:
384
347
  return False
@@ -389,10 +352,7 @@ def is_ollama_available():
389
352
  try:
390
353
  import requests
391
354
 
392
- base_url = os.getenv(
393
- "OLLAMA_BASE_URL",
394
- settings.llm.get("ollama_base_url", "http://localhost:11434"),
395
- )
355
+ base_url = get_db_setting("llm.ollama.url", "http://localhost:11434")
396
356
  logger.info(f"Checking Ollama availability at {base_url}/api/tags")
397
357
 
398
358
  try:
@@ -434,8 +394,7 @@ def is_lmstudio_available():
434
394
  try:
435
395
  import requests
436
396
 
437
- lmstudio_url = settings.llm.get("lmstudio_url", "http://localhost:1234")
438
- lmstudio_url = get_db_setting("llm.lmstudio_url", lmstudio_url)
397
+ lmstudio_url = get_db_setting("llm.lmstudio.url", "http://localhost:1234")
439
398
  # LM Studio typically uses OpenAI-compatible endpoints
440
399
  response = requests.get(f"{lmstudio_url}/v1/models", timeout=1.0)
441
400
  return response.status_code == 200
@@ -448,8 +407,7 @@ def is_llamacpp_available():
448
407
  try:
449
408
  from langchain_community.llms import LlamaCpp # noqa: F401
450
409
 
451
- model_path = settings.llm.get("llamacpp_model_path", "")
452
- model_path = get_db_setting("llm.llamacpp_model_path", model_path)
410
+ model_path = get_db_setting("llm.llamacpp_model_path")
453
411
  return bool(model_path) and os.path.exists(model_path)
454
412
  except Exception:
455
413
  return False
@@ -460,9 +418,8 @@ def get_available_providers():
460
418
  return get_available_provider_types()
461
419
 
462
420
 
463
- secrets_file = Path(SECRETS_FILE)
464
421
  AVAILABLE_PROVIDERS = get_available_providers()
465
- selected_provider = get_db_setting("llm.provider", settings.llm.provider).lower()
422
+ selected_provider = get_db_setting("llm.provider", "ollama").lower()
466
423
 
467
424
  # Log which providers are available
468
425
  logger.info(f"Available providers: {list(AVAILABLE_PROVIDERS.keys())}")
@@ -3,7 +3,6 @@ import logging
3
3
 
4
4
  from ..utilities.db_utils import get_db_setting
5
5
  from ..web_search_engines.search_engine_factory import get_search as factory_get_search
6
- from .config_files import settings
7
6
  from .llm_config import get_llm
8
7
 
9
8
  # Setup logging
@@ -13,9 +12,7 @@ logger = logging.getLogger(__name__)
13
12
  # Whether to check the quality search results using the LLM.
14
13
  QUALITY_CHECK_DDG_URLS = True
15
14
  # Whether to only retrieve snippets instead of full search results.
16
- SEARCH_SNIPPETS_ONLY = get_db_setting(
17
- "search.snippets_only", settings.search.snippets_only
18
- )
15
+ SEARCH_SNIPPETS_ONLY = get_db_setting("search.snippets_only", True)
19
16
 
20
17
 
21
18
  # Expose get_search function
@@ -29,7 +26,7 @@ def get_search(search_tool=None, llm_instance=None):
29
26
  """
30
27
 
31
28
  # Use specified tool or default from settings
32
- tool = search_tool or get_db_setting("search.tool", settings.search.tool)
29
+ tool = search_tool or get_db_setting("search.tool", "auto")
33
30
  logger.info(f"Creating search engine with tool: {tool}")
34
31
 
35
32
  # Get LLM instance (use provided or get fresh one)
@@ -39,23 +36,13 @@ def get_search(search_tool=None, llm_instance=None):
39
36
  params = {
40
37
  "search_tool": tool,
41
38
  "llm_instance": llm,
42
- "max_results": get_db_setting(
43
- "search.max_results", settings.search.max_results
44
- ),
45
- "region": get_db_setting("search.region", settings.search.region),
46
- "time_period": get_db_setting(
47
- "search.time_period", settings.search.time_period
48
- ),
49
- "safe_search": get_db_setting(
50
- "search.safe_search", settings.search.safe_search
51
- ),
39
+ "max_results": get_db_setting("search.max_results", 10),
40
+ "region": get_db_setting("search.region", "wt-wt"),
41
+ "time_period": get_db_setting("search.time_period", "all"),
42
+ "safe_search": get_db_setting("search.safe_search", True),
52
43
  "search_snippets_only": SEARCH_SNIPPETS_ONLY,
53
- "search_language": get_db_setting(
54
- "search.search_language", settings.search.search_language
55
- ),
56
- "max_filtered_results": get_db_setting(
57
- "search.max_filtered_results", settings.search.max_filtered_results
58
- ),
44
+ "search_language": get_db_setting("search.search_language", "English"),
45
+ "max_filtered_results": get_db_setting("search.max_filtered_results", 5),
59
46
  }
60
47
 
61
48
  # Log NULL parameters for debugging