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,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",
|
45
|
+
model_name = get_db_setting("llm.model", "gemma:latest")
|
50
46
|
if temperature is None:
|
51
|
-
temperature = get_db_setting("llm.temperature",
|
47
|
+
temperature = get_db_setting("llm.temperature", 0.7)
|
52
48
|
if provider is None:
|
53
|
-
provider = get_db_setting("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
|
-
|
81
|
-
common_params["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
|
-
|
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
|
-
|
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
|
-
|
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
|
111
|
+
if openai_endpoint_url is None:
|
135
112
|
openai_endpoint_url = get_db_setting(
|
136
|
-
"llm.
|
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 =
|
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 =
|
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",
|
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 =
|
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 =
|
258
|
-
|
259
|
-
|
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",
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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",
|
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",
|
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
|
-
|
44
|
-
),
|
45
|
-
"
|
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
|
-
|
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
|