local-deep-research 0.3.0__py3-none-any.whl → 0.3.2__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.
@@ -2,10 +2,10 @@
2
2
  Local Deep Research - A tool for conducting deep research using AI.
3
3
  """
4
4
 
5
- __version__ = "0.2.0"
6
5
  __author__ = "Your Name"
7
6
  __description__ = "A tool for conducting deep research using AI"
8
7
 
8
+ from .__version__ import __version__
9
9
  from .config.llm_config import get_llm
10
10
  from .config.search_config import get_search
11
11
  from .report_generator import get_report_generator
@@ -0,0 +1 @@
1
+ __version__ = "0.3.2"
@@ -3,6 +3,7 @@ import os
3
3
 
4
4
  from langchain_anthropic import ChatAnthropic
5
5
  from langchain_community.llms import VLLM
6
+ from langchain_core.language_models import FakeListChatModel
6
7
  from langchain_ollama import ChatOllama
7
8
  from langchain_openai import ChatOpenAI
8
9
 
@@ -248,9 +249,7 @@ def get_llm(model_name=None, temperature=None, provider=None, openai_endpoint_ur
248
249
 
249
250
  def get_fallback_model(temperature=None):
250
251
  """Create a dummy model for when no providers are available"""
251
- from langchain_community.llms.fake import FakeListLLM
252
-
253
- return FakeListLLM(
252
+ return FakeListChatModel(
254
253
  responses=[
255
254
  "No language models are available. Please install Ollama or set up API keys."
256
255
  ]
@@ -10,7 +10,7 @@
10
10
  "step": null,
11
11
  "type": "APP",
12
12
  "ui_element": "text",
13
- "value": "0.3.0",
13
+ "value": "0.3.2",
14
14
  "visible": false
15
15
  },
16
16
  "app.debug": {
@@ -3810,5 +3810,187 @@
3810
3810
  "ui_element": "number",
3811
3811
  "value": 100,
3812
3812
  "visible": true
3813
+ },
3814
+ "search.engine.web.pubmed.use_in_auto_search": {
3815
+ "category": "pubmed",
3816
+ "description": "Include PubMed in auto search mode",
3817
+ "editable": true,
3818
+ "max_value": null,
3819
+ "min_value": null,
3820
+ "name": "Include in Auto Search",
3821
+ "options": null,
3822
+ "step": null,
3823
+ "type": "SEARCH",
3824
+ "ui_element": "checkbox",
3825
+ "value": true,
3826
+ "visible": true
3827
+ },
3828
+ "search.engine.web.arxiv.use_in_auto_search": {
3829
+ "category": "arxiv",
3830
+ "description": "Include ArXiv in auto search mode",
3831
+ "editable": true,
3832
+ "max_value": null,
3833
+ "min_value": null,
3834
+ "name": "Include in Auto Search",
3835
+ "options": null,
3836
+ "step": null,
3837
+ "type": "SEARCH",
3838
+ "ui_element": "checkbox",
3839
+ "value": true,
3840
+ "visible": true
3841
+ },
3842
+ "search.engine.web.searxng.use_in_auto_search": {
3843
+ "category": "searxng",
3844
+ "description": "Include SearXNG in auto search mode",
3845
+ "editable": true,
3846
+ "max_value": null,
3847
+ "min_value": null,
3848
+ "name": "Include in Auto Search",
3849
+ "options": null,
3850
+ "step": null,
3851
+ "type": "SEARCH",
3852
+ "ui_element": "checkbox",
3853
+ "value": true,
3854
+ "visible": true
3855
+ },
3856
+ "search.engine.web.github.use_in_auto_search": {
3857
+ "category": "github",
3858
+ "description": "Include GitHub in auto search mode",
3859
+ "editable": true,
3860
+ "max_value": null,
3861
+ "min_value": null,
3862
+ "name": "Include in Auto Search",
3863
+ "options": null,
3864
+ "step": null,
3865
+ "type": "SEARCH",
3866
+ "ui_element": "checkbox",
3867
+ "value": true,
3868
+ "visible": true
3869
+ },
3870
+ "search.engine.web.wikipedia.use_in_auto_search": {
3871
+ "category": "wikipedia",
3872
+ "description": "Include Wikipedia in auto search mode",
3873
+ "editable": true,
3874
+ "max_value": null,
3875
+ "min_value": null,
3876
+ "name": "Include in Auto Search",
3877
+ "options": null,
3878
+ "step": null,
3879
+ "type": "SEARCH",
3880
+ "ui_element": "checkbox",
3881
+ "value": true,
3882
+ "visible": true
3883
+ },
3884
+ "search.engine.web.brave.use_in_auto_search": {
3885
+ "category": "brave",
3886
+ "description": "Include Brave search in auto search mode",
3887
+ "editable": true,
3888
+ "max_value": null,
3889
+ "min_value": null,
3890
+ "name": "Include in Auto Search",
3891
+ "options": null,
3892
+ "step": null,
3893
+ "type": "SEARCH",
3894
+ "ui_element": "checkbox",
3895
+ "value": false,
3896
+ "visible": true
3897
+ },
3898
+ "search.engine.web.google_pse.use_in_auto_search": {
3899
+ "category": "google_pse",
3900
+ "description": "Include Google PSE in auto search mode",
3901
+ "editable": true,
3902
+ "max_value": null,
3903
+ "min_value": null,
3904
+ "name": "Include in Auto Search",
3905
+ "options": null,
3906
+ "step": null,
3907
+ "type": "SEARCH",
3908
+ "ui_element": "checkbox",
3909
+ "value": false,
3910
+ "visible": true
3911
+ },
3912
+ "search.engine.web.serpapi.use_in_auto_search": {
3913
+ "category": "serpapi",
3914
+ "description": "Include SerpAPI in auto search mode",
3915
+ "editable": true,
3916
+ "max_value": null,
3917
+ "min_value": null,
3918
+ "name": "Include in Auto Search",
3919
+ "options": null,
3920
+ "step": null,
3921
+ "type": "SEARCH",
3922
+ "ui_element": "checkbox",
3923
+ "value": false,
3924
+ "visible": true
3925
+ },
3926
+ "search.engine.web.wayback.use_in_auto_search": {
3927
+ "category": "wayback",
3928
+ "description": "Include Wayback in auto search mode",
3929
+ "editable": true,
3930
+ "max_value": null,
3931
+ "min_value": null,
3932
+ "name": "Include in Auto Search",
3933
+ "options": null,
3934
+ "step": null,
3935
+ "type": "SEARCH",
3936
+ "ui_element": "checkbox",
3937
+ "value": false,
3938
+ "visible": true
3939
+ },
3940
+ "search.engine.local.local_all.use_in_auto_search": {
3941
+ "category": "local_all",
3942
+ "description": "Include local documents in auto search mode",
3943
+ "editable": true,
3944
+ "max_value": null,
3945
+ "min_value": null,
3946
+ "name": "Include in Auto Search",
3947
+ "options": null,
3948
+ "step": null,
3949
+ "type": "SEARCH",
3950
+ "ui_element": "checkbox",
3951
+ "value": true,
3952
+ "visible": true
3953
+ },
3954
+ "search.engine.local.personal_notes.use_in_auto_search": {
3955
+ "category": "personal_notes",
3956
+ "description": "Include personal notes in auto search mode",
3957
+ "editable": true,
3958
+ "max_value": null,
3959
+ "min_value": null,
3960
+ "name": "Include in Auto Search",
3961
+ "options": null,
3962
+ "step": null,
3963
+ "type": "SEARCH",
3964
+ "ui_element": "checkbox",
3965
+ "value": false,
3966
+ "visible": true
3967
+ },
3968
+ "search.engine.local.project_docs.use_in_auto_search": {
3969
+ "category": "project_docs",
3970
+ "description": "Include project documents in auto search mode",
3971
+ "editable": true,
3972
+ "max_value": null,
3973
+ "min_value": null,
3974
+ "name": "Include in Auto Search",
3975
+ "options": null,
3976
+ "step": null,
3977
+ "type": "SEARCH",
3978
+ "ui_element": "checkbox",
3979
+ "value": false,
3980
+ "visible": true
3981
+ },
3982
+ "search.engine.local.research_papers.use_in_auto_search": {
3983
+ "category": "research_papers",
3984
+ "description": "Include research papers in auto search mode",
3985
+ "editable": true,
3986
+ "max_value": null,
3987
+ "min_value": null,
3988
+ "name": "Include in Auto Search",
3989
+ "options": null,
3990
+ "step": null,
3991
+ "type": "SEARCH",
3992
+ "ui_element": "checkbox",
3993
+ "value": false,
3994
+ "visible": true
3813
3995
  }
3814
3996
  }
@@ -19,6 +19,7 @@ from flask import (
19
19
  from flask_wtf.csrf import generate_csrf
20
20
  from sqlalchemy.orm import Session
21
21
 
22
+ from ...utilities.db_utils import get_db_setting
22
23
  from ..database.models import Setting, SettingType
23
24
  from ..services.settings_service import (
24
25
  create_or_update_setting,
@@ -666,10 +667,7 @@ def api_get_available_models():
666
667
  try:
667
668
  current_app.logger.info("Attempting to connect to Ollama API")
668
669
 
669
- base_url = os.getenv(
670
- "OLLAMA_BASE_URL",
671
- "http://localhost:11434",
672
- )
670
+ base_url = get_db_setting("llm.ollama.url", "http://localhost:11434")
673
671
  ollama_response = requests.get(f"{base_url}/api/tags", timeout=5)
674
672
 
675
673
  current_app.logger.debug(
@@ -34,7 +34,7 @@ def check_env_setting(key: str) -> str | None:
34
34
  is not set.
35
35
 
36
36
  """
37
- env_variable_name = f"LDR_{"_".join(key.split(".")).upper()}"
37
+ env_variable_name = f"LDR_{'_'.join(key.split('.')).upper()}"
38
38
  env_value = os.getenv(env_variable_name)
39
39
  if env_value is not None:
40
40
  logger.debug(f"Overriding {key} setting from environment variable.")
@@ -53,7 +53,8 @@
53
53
  class="custom-dropdown-input"
54
54
  placeholder="${params.placeholder}"
55
55
  autocomplete="off"
56
- aria-haspopup="listbox">
56
+ aria-haspopup="listbox"
57
+ ${params.disabled ? "disabled" : ""}>
57
58
  <!-- Hidden input that will be included in form submission -->
58
59
  <input type="hidden" name="${params.input_id}" id="${params.input_id}_hidden" value="">
59
60
  <div class="custom-dropdown-list" id="${params.dropdown_id}-list"></div>
@@ -1475,7 +1476,8 @@
1475
1476
  help_text: setting.description || null,
1476
1477
  allow_custom: false,
1477
1478
  show_refresh: true, // Set to true for provider
1478
- data_setting_key: setting.key
1479
+ data_setting_key: setting.key,
1480
+ disabled: !setting.editable
1479
1481
  };
1480
1482
  inputElement = renderCustomDropdownHTML(dropdownParams);
1481
1483
  } else if (setting.key === 'search.tool') {
@@ -1487,7 +1489,8 @@
1487
1489
  help_text: setting.description || null,
1488
1490
  allow_custom: false,
1489
1491
  show_refresh: false, // No refresh for search tool
1490
- data_setting_key: setting.key
1492
+ data_setting_key: setting.key,
1493
+ disabled: !setting.editable
1491
1494
  };
1492
1495
  inputElement = renderCustomDropdownHTML(dropdownParams);
1493
1496
  } else if (setting.key === 'llm.model') { // ADD THIS ELSE IF
@@ -1501,7 +1504,8 @@
1501
1504
  allow_custom: true, // Allow custom for model
1502
1505
  show_refresh: true, // Show refresh for model
1503
1506
  refresh_aria_label: "Refresh model list",
1504
- data_setting_key: setting.key
1507
+ data_setting_key: setting.key,
1508
+ disabled: !setting.editable
1505
1509
  };
1506
1510
  inputElement = renderCustomDropdownHTML(dropdownParams);
1507
1511
  } else {
@@ -65,16 +65,43 @@ class MetaSearchEngine(BaseSearchEngine):
65
65
  )
66
66
 
67
67
  def _get_available_engines(self) -> List[str]:
68
- """Get list of available engines, excluding 'meta' and 'auto'"""
68
+ """Get list of available engines, excluding 'meta' and 'auto', based on user settings"""
69
69
  # Filter out 'meta' and 'auto' and check API key availability
70
70
  available = []
71
+
71
72
  for name, config_ in search_config().items():
72
73
  if name in ["meta", "auto"]:
73
74
  continue
74
75
 
76
+ # Determine if this is a local engine (starts with "local.")
77
+ is_local_engine = name.startswith("local.")
78
+
79
+ # Determine the appropriate setting path based on engine type
80
+ if is_local_engine:
81
+ # Format: search.engine.local.{engine_name}.use_in_auto_search
82
+ local_name = name.replace("local.", "")
83
+ auto_search_setting = (
84
+ f"search.engine.local.{local_name}.use_in_auto_search"
85
+ )
86
+ else:
87
+ # Format: search.engine.web.{engine_name}.use_in_auto_search
88
+ auto_search_setting = f"search.engine.web.{name}.use_in_auto_search"
89
+
90
+ # Get setting from database, default to False if not found
91
+ use_in_auto_search = get_db_setting(auto_search_setting, False)
92
+
93
+ # Skip engines that aren't enabled for auto search
94
+ if not use_in_auto_search:
95
+ logger.info(
96
+ f"Skipping {name} engine because it's not enabled for auto search"
97
+ )
98
+ continue
99
+
100
+ # Skip engines that require API keys if we don't want to use them
75
101
  if config_.get("requires_api_key", False) and not self.use_api_key_services:
76
102
  continue
77
103
 
104
+ # Skip engines that require API keys if the key is not available
78
105
  if config_.get("requires_api_key", False):
79
106
  api_key = config_.get("api_key")
80
107
  if not api_key:
@@ -82,9 +109,11 @@ class MetaSearchEngine(BaseSearchEngine):
82
109
 
83
110
  available.append(name)
84
111
 
85
- # Make sure we have at least one engine available
86
- if not available and "wikipedia" in search_config():
87
- available.append("wikipedia")
112
+ # If no engines are available, raise an error instead of falling back silently
113
+ if not available:
114
+ error_msg = "No search engines enabled for auto search. Please enable at least one engine in settings."
115
+ logger.error(error_msg)
116
+ raise RuntimeError(error_msg)
88
117
 
89
118
  return available
90
119
 
@@ -131,6 +160,17 @@ class MetaSearchEngine(BaseSearchEngine):
131
160
  except KeyError as e:
132
161
  logger.error(f"Missing key for engine {engine_name}: {str(e)}")
133
162
 
163
+ # Only proceed if we have engines available to choose from
164
+ if not engines_info:
165
+ logger.warning(
166
+ "No engine information available for prompt, using reliability-based sorting instead"
167
+ )
168
+ return sorted(
169
+ self.available_engines,
170
+ key=lambda x: search_config().get(x, {}).get("reliability", 0),
171
+ reverse=True,
172
+ )
173
+
134
174
  prompt = f"""You are a search query analyst. Consider this search query:
135
175
 
136
176
  QUERY: {query}